0%

Algorithm_双指针法

双指针法

双指针法可以分成两个部分:快慢指针,左右指针。前者解决主要解决链表中的问题,比如典型的判定链表中是否包含环;后者主要解决数组(或者字符串)中的问题,比如二分查找。

(注:这里的指针,并非专指c中指针的概念,而是指索引,游标或指针,可迭代对象等)

快慢指针常见算法

左右指针常见算法

左右指针在数组中实际是指两个索引值,一般初始化为 left = 0, right = nums.length - 1 。

一般我们会对数组进行排序,然后在进行比较时,通过移动指针来找到解。

二分查找

两个指针的算法都是很基础的,也是很简单的,通常只要取一头一尾进行移动比较即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int binarySearch(int[] nums, int target) 
{
int left = 0;
int right = nums.length - 1;
while(left <= right)
{
int mid = (right + left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
}

两数之和

Leetcode:167——两数之和II-输入有序数组

题目描述:在有序数组中找出两个数,使它们的和为 target。

在进行数组元素相加后比较之类的问题,都可以采取双指针方式进行求解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public int[] twoSum(int[] numbers, int target) {
int right=0;
int left=numbers.length-1;
int []output = new int[2];
while(right<left)
{
if(numbers[right]+numbers[left]==target){
output[0]=right+1;
output[1]=left+1;
break;
}
else if(numbers[right]+numbers[left]<target)
{
right++;
}
else
{
left--;
}
}
return output;
}
}

两数平方和

Leetcode:633——平方数之和

题目描述:给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2^ + b^2^ = c。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public boolean judgeSquareSum(int c) {
int right = 0,left =(int)Math.sqrt(c);
while(right<=left)
{
if(Math.pow(right,2)+Math.pow(left,2)==c)
{
return true;
}
else if(Math.pow(right,2)+Math.pow(left,2)<c)
{
right++;
}
else
{
left--;
}
}
return false;
}
}

Leetcode:18

左右指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
if(nums==null||nums.length<4)
{
return result;
}
Arrays.sort(nums);
int length=nums.length;
//一个指向最小的值,一个指向最大的值
int head,tail;
int left,right;
for(head=0;head<length-3;head++)
{
//在有相同的数的前提下,移动到最右边的数
if(head>0&&nums[head]==nums[head-1])
continue;
//如果当前可以取得的最小值比目标值大的话,直接退出。
int min=nums[head]+nums[head+1]+nums[head+2]+nums[head+3];
if(min>target)break;
//如果当前取得的最大值比目标值小的话,将head往后移动
int max = nums[head]+nums[length-1]+nums[length-2]+nums[length-3];
if(max<target)continue;
for(left=head+1;left<length-2;left++)
{
tail = length-1;
right = left+1;
if(left>head+1&&nums[left-1]==nums[left])continue;
min = nums[head]+nums[left]+nums[left+1]+nums[left+2];
if(min>target)continue;
max = nums[head]+nums[left]+nums[tail-1]+nums[tail];
if(max<target)
{
continue;
}
while(right<tail)
{
int all = nums[head]+nums[left]+nums[right]+nums[tail];
if(all==target)
{
result.add(Arrays.asList(nums[head],nums[left],nums[right],nums[tail]));
right++;
while(right>left&&right<tail&&nums[right-1]==nums[right])
{
right++;
}
tail--;
while(tail>left&&nums[tail]==nums[tail+1])
{
tail--;
}
}
else if(all>target)
{
tail--;
}
else if(all<target)
{
right++;
}

}
}
}
return result;
}

}