> 文档中心 > 五月集训(第5天)——双指针

五月集训(第5天)——双指针


前言:

五月集训,前面为学习内容,想要一起学习的可以看一看,最后的才是五月集训每天的作业。

一、知识点

双指针主要应用于数组以及链表问题中;
对于数组而言,就是定义两个指针,相向移动,不断进行问题的求解和判断,最终得到问题的解。
对于链表而言,就是定义一快一慢(即快慢针)两个指针,不断进行迭代求解问题。

二、课堂习题

这里的题均出自《算法零基础100讲》
我们先对数组的双指针问题进行练习,在数组中,双指针相向移动时,可能是同速的,也可能是不同速的,先做几道不同速的题。
344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

i指针放在头部,j指针放在尾部,相向移送的同时不断交换元素即可。

class Solution {    public void reverseString(char[] s) { int i = 0,j = s.length-1; while(i < j){     char temp = s[i];     s[i] = s[j];     s[j] = temp;     ++i;--j; }    }}

五月集训(第5天)——双指针
2108. 找出数组中的第一个回文字符串

给你一个字符串数组 words ,找出并返回数组中的 第一个回文字符串 。如果不存在满足要求的字符串,返回一个 空字符串 “” 。

回文字符串 的定义为:如果一个字符串正着读和反着读一样,那么该字符串就是一个 回文字符串 。

将每个字符串提取出来,然后依次做回文串判断。

class Solution {    public String firstPalindrome(String[] words) { for(String str : words){     int i = 0,j = str.length()-1;     boolean f = true;;     while(i < j){  if(str.charAt(i) == str.charAt(j)){      ++i;--j;  }else{      f = false;      break;  }     }      if(f){  return str;     } } return "";    }}

五月集训(第5天)——双指针
2000. 反转单词前缀

给你一个下标从 0 开始的字符串 word 和一个字符 ch 。找出 ch 第一次出现的下标 i ,反转 word 中从下标 0
开始、直到下标 i 结束(含下标 i )的那段字符。如果 word 中不存在字符 ch ,则无需进行任何操作。

例如,如果 word = “abcdefd” 且 ch = “d” ,那么你应该 反转 从下标 0 开始、直到下标 3 结束(含下标 3
)。结果字符串将会是 “dcbaefd” 。 返回 结果字符串 。

示例 1:

输入:word = “abcdefd”, ch = “d” 输出:“dcbaefd” 解释:“d” 第一次出现在下标 3 。 反转从下标
0 到下标 3(含下标 3)的这段字符,结果字符串是 “dcbaefd” 。

遍历一遍字符串的元素,找到第一个目标字符小标j,然后i=0与j相向移动反转字符串前缀。

class Solution {    public String reversePrefix(String word, char ch) { char[] words = word.toCharArray(); int i = 0,j = 1; for(j = 0;j < words.length;++j){     if(words[j] == ch){  break;     } } if(j == words.length){     return word; } while(i < j){     char temp = words[i];     words[i] = words[j];     words[j] = temp;     ++i;--j; } return new String(String.valueOf(words));    }}

五月集训(第5天)——双指针
151. 颠倒字符串中的单词

给你一个字符串 s ,颠倒字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串
s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = “the sky is blue” 输出:“blue is sky the”
示例 2:
输入:s = " hello world " 输出:“world hello” 解释:颠倒后的字符串中不能存在前导空格和尾随空格。
示例3:
输入:s = “a good example” 输出:“example good a”
解释:如果两个单词间有多余的空格,颠倒后的字符串需要将单词间的空格减少到仅有一个。

将解题过程分为三个部分:
将整体字符串翻转,正常反转就可以;
每个单词进行翻转,需要双指针,依次找到每个单词的开头和结尾,并进行翻转;
删除多余的空格。

class Solution {    public String reverseWords(String s) { char[] words = s.toCharArray(); int i = 0,j = words.length-1; reverse(words,i,j); word_reverse(words); return delete(words);    }    public void reverse(char[] words,int i,int j){ while(i < j){     char temp = words[i];     words[i] = words[j];     words[j] = temp;     ++i;--j; }    }    public void word_reverse(char[] words){ int n = words.length; int i = 0,j = 0; while(j < n){     while(i < n && words[i] == ' '){  ++i;     }     j = i;     while(j < n && words[j] != ' '){  ++j;     }     reverse(words,i,j-1);     i = j; }    }    public String delete(char[] words){ int n = words.length; int i = 0,j = 0; while(j < n){     while(j < n && words[j] == ' '){  ++j;     }     while(j < n && words[j] != ' '){  words[i++] = words[j++];     }     while(j < n && words[j] == ' '){  ++j;     }     if(j < n){  words[i++] = ' ';     } } return String.valueOf(words).substring(0,i);    }}

五月集训(第5天)——双指针

三、作业

917. 仅仅反转字母
167. 两数之和 II - 输入有序数组
165. 比较版本号
443. 压缩字符串
解题思路:
1.
(1)定义i,j两个指针,i指向字符串开头,j指向结尾;
(2)当指向的元素不是字母是,不断相向移动;
(3)将字母交换。
2.
(1)定义两个指针i,j指向数组的两端;
(2)和等于目标值,则返回下标+1,大于目标值–j,小于目标值++i。
3.
(1)定义两个指针分别指向两个版本号;
(2)以’.'为分界,进行计数;
(3)两个版本号不相等则按照题意返回答案。
4.
(1)定义两个指针i,j一个记录一种字符的开始,一个记录结束;
(2)定义一个下标指针用来放改变后的元素;
(3)种类不同时将这种元素放入数组,并判断重复次数是否>1,是的话将数字放进去。
需要注意,数字有可能>10,需要取余循环放入。
代码以及结果:
1.

class Solution {    public String reverseOnlyLetters(String s) { char[] words = s.toCharArray(); int n = words.length; int i = 0,j = n - 1; while(i < j) {     while (i < j && !Character.isLetter(words[i])) i++;     while (i < j && !Character.isLetter(words[j])) j--;     if (i < j) {  char temp = words[i];  words[i++] = words[j];  words[j--] = temp;     } } return String.valueOf(words);    }}

五月集训(第5天)——双指针
2.

class Solution {    public int[] twoSum(int[] numbers, int target) { int i = 0,j = numbers.length-1; while(i < j){     int sum = numbers[i] + numbers[j];     if(sum == target){  return new int[]{i+1,j+1};     }else if(sum > target){  --j;     }else{  ++i;     } } return null;    }}

五月集训(第5天)——双指针
3.

class Solution {    public int compareVersion(String version1, String version2) { int n1 = version1.length(),n2 = version2.length(); int i = 0,j = 0; while(i < n1 || j < n2){     int temp1 = 0;     while(i < n1 && version1.charAt(i) != '.'){  temp1 = temp1*10 + version1.charAt(i) - '0';  ++i;     }     ++i;     int temp2 = 0;     while(j < n2 && version2.charAt(j) != '.'){  temp2 = temp2*10 + version2.charAt(j) - '0';  ++j;     }     ++j;     if(temp1 != temp2){  return temp1 > temp2 ? 1 : -1;     } } return 0;    }}

五月集训(第5天)——双指针
4.

class Solution {    public int compress(char[] chars) { int n = chars.length; int i = 0, j = 0; int index = 0; while(j < n){     j = i;     while(j < n && chars[i] == chars[j]){  ++j;     }     int cnt = j - i;     chars[index++] = chars[i];     if(cnt > 1){  int start = index,end = index;  while(cnt != 0){      chars[end++] = (char)((cnt % 10) + '0');      cnt /= 10;  }  reverse(chars,start,end-1);  index = end;     }     i = j; } return index;    }    void reverse(char[] chars, int start, int end) { while (start < end) {     char t = chars[start];     chars[start] = chars[end];     chars[end] = t;     start++; end--; }    }}

五月集训(第5天)——双指针

四、总结

对于算法的掌握还是不够熟练,需要进行反复训练!
另外,剩下的课堂训练题目留到下个月的集训啦(●ˇ∀ˇ●)