注:双指针不是指真正意义上的指针,它是一种思想。
题目1:力扣167. 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:返回的下标值(index1 和 index2)不是从零开始的。你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
一句话描述:有序数组中找两个数,使它们和为target.
想法:双指针
一个指针指向最小元素,一个指针指向最大元素。因为题目说是有序数组,所以一个指向最左边,一个指向最右边。
- 定义sum=左指针+右指针
- 如果sum>target,说明sum太大了,得缩小,右指针左移
- 如果sum<target,说明sum太小了,得扩大,左指针右移
class Solution {
public int[] twoSum(int[] numbers, int target) {
//注意:这里的左右指针都是指下标
int left = 0;
int right = numbers.length - 1;
while(left < right){
int sum = numbers[left] + numbers[right];
if(sum > target){
right--;
}
if(sum < target){
left++;
}
if(sum == target){
return new int[]{left + 1, right + 1};
}
}
return null;
}
}
题目2:力扣633. 平方数之和
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
示例 1:
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
想法
和第一题类似,只不过我们要确定右指针指向谁。因为要求平方和,所以我们开根号,强制转换为int类型,这个数就是右指针指向的数。
class Solution {
public boolean judgeSquareSum(int c) {
int left = 0;
int right = (int)Math.sqrt(c); //这里注意强制转换
while(left <= right){ //这里有=号,例如2的情况,1*1+1*1=2
int sum = left*left + right*right;
if(sum > c){
right--;
}else if(sum < c){
left++;
}else{
return true;
}
}
return false;
}
}
题目3:力扣345. 反转字符串中的元音字母
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
示例 1:
输入:"hello"
输出:"holle"
示例 2:输入:"leetcode"
输出:"leotcede"
想法
这道题就比上面两道复杂了,不过大概思想是差不多的。
元音字母:aeiouAEIOOU(这里考虑大小写)
- 两个指针,一个指向给定字符串s的最左端,一个指向最右端
- 判断第一个字符是不是元音字母,不是的话,直接复制到结果result中.result[i]=ci,i++
- 同理判断最后一个字符是不是元音字母。
- 最后如果两边都是元音字符,我们就交换两边字符
class Solution {
//Arrays.asList();将数组转为集合。
private final static HashSet<Character> vowels = new HashSet<>(Arrays.asList('a','e','i','o','u','A','E','I','O','U'));
public String reverseVowels(String s) {
int i = 0, j = s.length() - 1;
char[] result = new char[s.length()];
while(i <= j){
//ci指向s的最左边,充当左指针,cj指向s的最右边,充当右指针
char ci = s.charAt(i);
char cj = s.charAt(j);
//左指针不是元音字符,将字符原封不动的复制到最终结果result中
if(!vowels.contains(ci)){
result[i++] = ci;
}else if(!vowels.contains(cj)){
result[j--] = cj;
}else{
result[i++] = cj;
result[j--] = ci;
}
}
return new String(result);
}
}
题目4:力扣680. 验证回文字符串 Ⅱ
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:输入: "abca"
输出: True
解释: 你可以删除c字符。
想法
比传统的双指针多了一步,就是要判断删除左指针或者右指针后,这个字符串是不是回文字符串。
/*class Solution {
public boolean validPalindrome(String s) {
// p1指向第一个,p2指向最后一个
// 当s.charAt(p1)==s.charAt(p2)时,p1++,p2--
// 当不等于的时候,该怎么办???
// ==>当不等于的时候,就需要删除一个字符了。
// ==>删除一个字符,可以重新定义一个函数。
// ==>比如abca,我们可以删除b,也可以删除c,此时对应(p1+1,p2),(p1,p2-1)
int p1=0,p2=s.length()-1;
while(p1 < p2){ //这里p1,p2同时指向一个数,不影响结果
if(s.charAt(p1) != s.charAt(p2)){
return isPalindrome(s,p1+1,p2) || isPalindrome(s,p1,p2-1);
}
p1++;
p2--;
}
return true;
}
private boolean isPalindrome(String s, int p1,int p2){
while(p1 < p2){
if(s.charAt(p1) != s.charAt(p2)){
return false;
}
p1++;
p2--;
}
return true;
}
}*/
class Solution {
public boolean validPalindrome(String s) {
int i = 0, j = s.length() - 1;
while(i < j){
if(s.charAt(i) != s.charAt(j)){
//这里对应了删除左指针字符或者删除右指针字符
return isPalindrome(s, i + 1, j) || isPalindrome(s, i, j - 1);
}
i++;
j--;
}
return true;
}
//判断是否是回文数字,这里不考虑是否要删除字符,只判断左指针与右指针的字符是否相同
private boolean isPalindrome(String s, int i, int j){
while(i < j){
if(s.charAt(i++) != s.charAt(j--))
return false;
}
return true;
}
}