FourSum

复制代码
package LeetCode;

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

/**
 * 18.四数之和
 * 给你一个由 n 个整数组成的数组nums ,和一个目标值 target 。
 * 请你找出并返回满足下述全部条件且不重复的四元组[nums[a], nums[b], nums[c], nums[d]](若两个四元组元素一一对应,则认为两个四元组重复):
 *
 * 0 <= a, b, c, d< n
 * a、b、c 和 d 互不相同
 * nums[a] + nums[b] + nums[c] + nums[d] == target
 * 你可以按 任意顺序 返回答案 。
 * */
public class FourSum {
    public static void main(String[] args) {

    }

//    public static 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;
//    }

/**
 * 双指针 + 排序 + 剪枝
 * 解题思路:
 * 1.在三数之和的基础上增加一层循环,再利用双指针,但在前两层循环中使用了最大最小值来提前进行判断,节省了时间,双指针中也进行了去重的操作
 * 2.在确定第一个数之后,如果 nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target,说明此时剩下的三个数无论取什么值,
 * 四个数之和一定大于target,因此退出第一次循环
 * 3.在确定第一个数之后,如果 nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target,说明此时剩下的三个数无论取什么值,
 * 四个数之和一定小于 target,因此第一重循环直接进入下一轮,枚举nums[i+1]
 * 4.在确定前两个数之后,如果 nums[i] + nums[j] + nums[j+1] + nums[j+2] > target,说明此时剩下的两个数无论什么值,
 * 四个数之和一定大于target,因此退出第二重循环
 * 5.在确定前两个数之后,如果nums[i] + nums[j] + nums[n-2] + nums[n-1] < target,说明此时剩下的两个数无论取什么值,
 * 四数之和一定小于 target,因此第二重循环直接进入下一轮。枚举 nums[j+1]
 */


    public List<List<Integer>> fourSum2(int[] nums, int target) {
        List<List<Integer>> quadruplets = new ArrayList<>(); // 定义一个返回值
        if (nums == null || nums.length < 4) {
            return quadruplets;
        }
        Arrays.sort(nums);
        int length = nums.length;
        //定义4个指针,i,j,left,right,i从0开始遍历,j从i+1开始遍历,留下left和right作为双指针
        for (int i = 0; i < length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) { //当i的值和前面的值相等时忽略
                continue;
            }
            //获取当前最小值,如果最小值比目标值大,说明后面越来越大,根本不可能存在
            if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
                break; // 这里使用break,直接退出此次循环,因为后面的数只会更大
            }
            // 获取当前最大值,如果最大值比目标值小,说明后面越来越小,根本不可能存在,忽略
            if (nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
                continue; // 这里使用continue,继续下一次循环,因为下一次循环有更大的数
            }
            // 第二层循环j,初始值指向 i+1
            for (int j = i+1; j < length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) { // 当j的值与前面的值相等时忽略
                    continue;
                }
                if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                    break;
                }
                if (nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
                    continue;
                }
                int left = j + 1, right = length - 1;
                // 双指针遍历,如果等于目标值,left++并去重,当当前和大于目标值时right--,当当前和小于目标值时left++
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        left++; // left先+1之后,和它前面的left-1进行比较,若后+1,则和它后面的left+1 进行比较
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        right--;
                        while (left < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return quadruplets;
    }
}
复制代码

 

posted @   坤坤无敌  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示