LeetCode算法题--双指针

0011 盛最多的水

题目

思路:最初我们考虑由最外围两条线段构成的区域。现在,为了使面积最大化,我们需要考虑更长的两条线段之间的区域。如果我们试图将指向较长线段的指针向内侧移动,矩形区域的面积将受限于较短的线段而不会获得任何增加。但是,在同样的条件下,移动指向较短线段的指针尽管造成了矩形宽度的减小,但却可能会有助于面积的增大。因为移动较短线段的指针会得到一条相对较长的线段,这可以克服由宽度减小而引起的面积减小

JAVA

package com.Manigoat;

public class Test0011盛最多的水 {

    public static void main(String[] args) {
        int height[]={1,8,6,2,5,4,8,3,7};
        int answer=maxArea(height);
        System.out.println(answer);
    }

    public static int maxArea(int[] height) {
        int max = 0, l = 0, r = height.length - 1;
        while (l < r) {
            max = Math.max(max, Math.min(height[l], height[r]) * (r - l));
            if (height[l] < height[r])
                l++;
            else
                r--;
        }
        return max;
    }
}

C++

int maxArea(vector<int>& height) {
	int answer=0;
	int l=0;
	int r=height.size()-1;
	while(l<r){
		int temp= min(height[l],height[r])*(r-l);
		answer=max(answer,temp);
		if(height[l]<height[r]){
			l++;
		}else{
			r--;
		}
	}
	return answer;        
}

0015 三数之和

题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

JAVA

package com.Manigoat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test0015三数之和 {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList();
        int len = nums.length;
        if(nums == null || len < 3) return ans;
        Arrays.sort(nums); // 排序
        for (int i = 0; i < len ; i++) {
            if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
            int L = i+1;
            int R = len-1;
            while(L < R){
                int sum = nums[i] + nums[L] + nums[R];
                if(sum == 0){
                    ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
                    while (L<R && nums[L] == nums[L+1]) L++; // 去重
                    while (L<R && nums[R] == nums[R-1]) R--; // 去重
                    L++;
                    R--;
                }
                else if (sum < 0) L++;
                else if (sum > 0) R--;
            }
        }
        return ans;
    }
}

C++

vector<vector<int>> threeSum(vector<int>& nums) {
    int l1=0;
    vector<vector<int>> res;
    sort(nums.begin(), nums.end());
    if(nums.size()<3)return res;
    for(int i=0;i<nums.size()-2; i++){
        if(i>0&&nums[i]==nums[i-1])continue;//去重
        int l=i+1;
        int r=nums.size()-1;
        while(l<r){
            int temp =nums[l]+nums[r]+nums[i];
            if(temp==0){
                res.push_back(vector<int>{nums[i],nums[l],nums[r]});
                while(l<r&&nums[l+1]==nums[l]){
                    l++;
                }
                while(l<r&&nums[r-1]==nums[r]){
                    r--;
                }
                l++;
                r--;
            }else if(temp<0){
                l++;

            }else{
                r--;
            }
        }
    }
    return res;
}

0016 最接近的三数之和

题目:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

思路:与上题类似

JAVA

public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int ans = nums[0] + nums[1] + nums[2];
        for(int i=0;i<nums.length;i++) {
            int start = i+1, end = nums.length - 1;
            while(start < end) {
                int sum = nums[start] + nums[end] + nums[i];
                if(Math.abs(target - sum) < Math.abs(target - ans))
                    ans = sum;
                if(sum > target)
                    end--;
                else if(sum < target)
                    start++;
                else
                    return ans;
            }
        }
        return ans;
}

C++

int threeSumClosest(vector<int>& nums, int target) {
        if(nums.size()<3){
        	return 0;
		}
		sort(nums.begin(), nums.end());
		int size= nums.size();
		int answer=nums[0]+nums[1]+nums[2];
		for(int i=0;i<size;i++){
			int l= i+1;
			int r= size-1;
			while(l<r){
				int res= nums[i]+nums[l]+nums[r];
				if(abs(answer-target)>abs(res-target)){
					answer=res;
				}
				if(res<target){
					l++;
				}else if(res>target){
					r--;
				}else{
					return answer;
				}
			}
		}
        return answer;
}

0018 四数之和

题目:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c*和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

思路:枚举前两个数i,j,然后剩下两个数使用双指针。

package com.Manigoat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test0018四数之和 {

    public static List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new ArrayList();
        int len = nums.length;
        if(nums == null || len < 4) return ans;
        Arrays.sort(nums); // 排序
        for (int k = 0; k <len-3 ; 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[len-1]+nums[len-2]+nums[len-3];
            if(max1<target){
                continue;
            }
            for (int i = k+1; i <len-2 ; i++) {
                /*去重*/
                if(i>k+1&&nums[i]==nums[i-1]) {
                    continue;
                }
                /*定义指针j指向i+1*/
                int j=i+1;
                /*定义指针h指向数组末尾*/
                int h=len-1;
                /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/
                int min=nums[k]+nums[i]+nums[j]+nums[j+1];
                if(min>target){
                    continue;
                }
                /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
                int max=nums[k]+nums[i]+nums[h]+nums[h-1];
                if(max<target){
                    continue;
                }
                while(j<h){
                    int curr=nums[k]+nums[i]+nums[j]+nums[h];
                    if(curr==target){
                        ans.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 ans;
    }
}

C++

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    	vector<vector<int>>res;
		if(nums.size()<4){
    		return res;
		}
		sort(nums.begin(),nums.end());
		int size= nums.size();
		for(int i=0;i<size-3;i++){
			/*去重*/
            if(i>0&&nums[i]==nums[i-1]) {
                continue;
           	}
			for(int j=i+1;j<size-2;j++){
				int l=j+1;
				int r=size-1;
				/*去重*/
            	if(j>i+1&&nums[j]==nums[j-1]) {
                	continue;
           		}
           		while(l<r){
           			int sum=nums[i]+nums[j]+nums[l]+nums[r];
           			if(sum==target){
           				res.push_back(vector<int>{nums[i],nums[j],nums[l],nums[r]});
           				while(l<r&&nums[l]==nums[l+1]){
           					l++;	
						}
						while(l<r&&nums[r]==nums[r-1]){
           					r--;	
						}
						l++;
						r--;
					}else if(sum>target){
						r--;
					}else{
						l++;
					}
				}
			}
		}
		return res;
}

0026 删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度.

JAVA

public int removeDuplicates(int[] nums) {
    if (nums.length == 0) return 0;
    int i = 0;
    for (int j = 1; j < nums.length; j++) {
        if (nums[j] != nums[i]) {
            i++;
            nums[i] = nums[j];
        }
    }
    return i + 1;
}

C++

int removeDuplicates(vector<int>& nums) {
	if (nums.size() < 2) return nums.size();
    int j=0;
    for(int i=0;i<nums.size();i++){
    	if(i>0&&nums[i]==nums[i-1]){
    		continue;
		}
		nums[j++]=nums[i];
	}
	return j;
}

0027 移除元素

给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。

JAVA

public int removeElement(int[] nums, int val) {
    int i = 0;
    for (int j = 0; j < nums.length; j++) {
        if (nums[j] != val) {
            nums[i] = nums[j];
            i++;
        }
    }
    return i;
}

C++

int removeElement(vector<int>& nums, int val) {
	if(nums.size()<1){
		return nums.size();
	}        
	int j=0;
	for(int i=0;i<nums.size();i++){
		if(nums[i]==val){
			continue;
		}
		nums[j++]=nums[i];
	}
	return j;
}

0283 移动零

**题目:**给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

**法一:**第一遍处理所有非零项,第二遍置零。

**法二:**我们使用两个指针ij,只要nums[i]!=0,我们就交换nums[i]nums[j]

public void moveZeroes(int[] nums) {
    if(nums==null) {
        return;
    }
    //第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
    int j = 0;
    for(int i=0;i<nums.length;++i) {
        if(nums[i]!=0) {
            nums[j++] = nums[i];
        }
    }
    //非0元素统计完了,剩下的都是0了
    //所以第二次遍历把末尾的元素都赋为0即可
    for(int i=j;i<nums.length;++i) {
        nums[i] = 0;
    }
}


public void moveZeroes(int[] nums) {
    if(nums==null) {
        return;
    }
    //两个指针i和j
    int j = 0;
    for(int i=0;i<nums.length;i++) {
        //当前元素!=0,就把其交换到左边,等于0的交换到右边
        if(nums[i]!=0) {
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j++] = tmp;
        }
    }
}

0202 快乐数(黑科技:快慢指针)

**题目:**一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

JAVA

public int getNext(int n) {
    int totalSum = 0;
    while (n > 0) {
        int d = n % 10;
        n = n / 10;
        totalSum += d * d;
    }
    return totalSum;
}

public boolean isHappy(int n) {
    int slowRunner = n;
    int fastRunner = getNext(n);
    while (fastRunner != 1 && slowRunner != fastRunner) {
        slowRunner = getNext(slowRunner);
        fastRunner = getNext(getNext(fastRunner));
    }
    return fastRunner == 1;
}

C++

int getNext(int n) {
    int totalSum = 0;
    while (n > 0) {
        int d = n % 10;
        n = n / 10;
        totalSum += d * d;
    }
    return totalSum;
}

bool isHappy(int n) {
    int slowRunner = n;
    int fastRunner = getNext(n);
    while (fastRunner != 1 && slowRunner != fastRunner) {
        slowRunner = getNext(slowRunner);
        fastRunner = getNext(getNext(fastRunner));
    }
    return fastRunner == 1;
}
原创文章 14 获赞 10 访问量 580

猜你喜欢

转载自blog.csdn.net/qq_43672466/article/details/105001078