双指针问题
单纯的双指针问题很简单,只需要排序后一前一后互相靠拢
对于双指针的"变种",三个或更多,只需要用一个原则:定一议二
三指针
例如三数之和,只需"定"一个指针,另外两个相互靠拢,即真正的"双指针"是另外两个
public List<List<Integer>> threeSum(int[] nums) {
//对给定数组排序
Arrays.sort(nums);
LinkedList<List<Integer>> list = new LinkedList<>();
//i递增遍历数组,j,k作为双指针,一前一后
int i = 0, j, k;
while(i <= nums.length-3){
//i!=0:避免数组下标越界
//如果nums[i] == nums[i-1],直接跳过,是为了去重,前提是数组已经排好序
if(i != 0 && nums[i] == nums[i-1]){
i++;
continue;
}else{
j = i+1;
k = nums.length-1;
while(j < k){
//同理,为了去重
if (j != i+1 && nums[j] == nums[j-1]){
j++;
continue;
//同理,为了去重
}else if (k != nums.length-1 && nums[k] == nums[k+1]){
k--;
continue;
}else {
if(nums[i] + nums[j] + nums[k] == 0){
list.add(new LinkedList<Integer>());
list.getLast().add(nums[i]);
list.getLast().add(nums[j]);
list.getLast().add(nums[k]);
j++;k--;
}else if(nums[i] + nums[j] + nums[k] < 0){
j++;
}else{
k--;
}
}
}
i++;
}
}
return list;
}
四指针
四数之和,"定"一个指针后再"定"一个指针,另外两个指针相互靠拢
public List<List<Integer>> fourSum(int[] nums,int target){
//定义一个返回值
List<List<Integer>> result=new ArrayList<>();
//当数组为null或元素小于4个时,直接返回
if(nums==null||nums.length<4){
return result;
}
//对数组进行从小到大排序
Arrays.sort(nums);
//数组长度
int length=nums.length;
//定义4个指针k,i,j,h k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值
for(int k=0;k<length-3;k++){
//当k的值与前面的值相等时跳过
if(k>0&&nums[k]==nums[k-1]){
continue;
}
//获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏
int min1=nums[k]+nums[k+1]+nums[k+2]+nums[k+3];
if(min1>target){
break;
}
//获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略
int max1=nums[k]+nums[length-1]+nums[length-2]+nums[length-3];
if(max1<target){
continue;
}
//第二层循环i,初始值指向k+1
for(int i=k+1;i<length-2;i++){
//当i的值与前面的值相等时跳过
if(i>k+1&&nums[i]==nums[i-1]){
continue;
}
//定义指针j指向i+1
int j=i+1;
//定义指针h指向数组末尾
int h=length-1;
//获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略
int min=nums[k]+nums[i]+nums[j]+nums[j+1];
if(min>target){
break;
}
//获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略
int max=nums[k]+nums[i]+nums[h]+nums[h-1];
if(max<target){
continue;
}
//开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++
while (j<h){
int curr=nums[k]+nums[i]+nums[j]+nums[h];
if(curr==target){
result.add(Arrays.asList(nums[k],nums[i],nums[j],nums[h]));
j++;
while(j<h&&nums[j]==nums[j-1]){
j++;
}
h--;
while(j<h&&i<h&&nums[h]==nums[h+1]){
h--;
}
}else if(curr>target){
h--;
}else {
j++;
}
}
}
}
return result;
}
时间复杂度
"n指针"问题需要n-2个作为"定针",另外两个相互靠拢,所以"n指针"的时间复杂度只能降到(n-1)次方

浙公网安备 33010602011771号