LeetCode总结-K-Sum问题

最近在刷 LeetCode 上的题为找工作提前做准备,在刷 Array 类问题的 Easy 难度的题的时候觉得还好,大部分的题还是能够想得出来,但是在刷到 Medium 难度的时候,明显感觉难度提升了,其中有一类题型连续出现引起了我的注意,就是 K Sum 问题。

K Sum问题就是,给出一个数作为 target,和一个数组作为待查数组,在这个待查数组里找出 K 个数之和等于 target.

最简单的 2 Sum

2 Sum应该是最简单的了,但是它是解决我们后面 3 Sum和 4 Sum 问题的最小子问题了。如果一开始就用暴力循环的方法当然是做的出来,但是,一是 LeetCode 可能会判超时(在 3 Sum 和 4 Sum 问题中确实会超时) ,二是暴力穷举也没什么意思。最简单的穷举法是 O(n^2) 的时间复杂度,那么我们可以将数组排好序后,用头尾两个指针一次迭代即可找出,时间复杂度降为了 O(nlogn).

3 Sum 问题

接下来就是3 Sum问题了,用暴力法 LeetCode 已经给出了超时的提醒了,所以O(n^3)的时间复杂度肯定是不能接受的,那么我们可以想像如何分解问题,毕竟3 Sum=2 Sum + 1 Sum,那么我们完全可以用将上面 2 Sum 问题的解法嵌入到一层循环中,也就是先排序然后一个指针从头开始循环,在数组的其他数中找出 2个数的和加上这个指针指向的数的和等于 target就行了,也就是说我们已经有了循环指针指向的这个数 V,那么我们只需要在其他书中找出 num1+num2=target-V就行了,这就又把问题带回到了2 Sum上,中不过多了一层循环,时间复杂度就降为了 O(n^2)。

代码实例:

/*注题目
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.
*/
public class Solution {
   public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result=new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++)
        {
            if(i>0&&nums[i]==nums[i-1]) //跳过相同的数以避免相同的List的产生
            {
                continue;
            }
            find(result,nums,i+1,nums.length-1,nums[i]);
        }
       return result;
   }
    public static void find(List<List<Integer>> res,int[] nums,int start,int end,int target)
    {
        int l=start,r=end;
        while(l<r)
        {
            if(target+nums[l]+nums[r]==0)
            {
                List<Integer> list=new ArrayList<>();
                list.add(target);
                list.add(nums[l]);
                list.add(nums[r]);
                res.add(list);
                while(l<r&&nums[l]==nums[l+1])//跳过相同的数
                {
                    l++;
                }
                while(l<r&&nums[r]==nums[r-1])//跳过相同的数
                {
                    r--;
                }
                l++;
                r--;
            }else if(target+nums[l]+nums[r]<0)//如果和小于0(target),l右移扩大和
            {
                l++;
            }else//否则左移缩小和
            {
                r--;
            }
        }
    }
        
}

3Sum Closest 问题

3Sum Closest 问题是3 Sum 问题的一个变种,意思就是给出一个 target,找出数组中最接近 target的 3 个数之和。这道题和 3 Sum 很像,不同的是需要用一个临时变量来保存当前最接近 target 的值,值得注意的是我们需要求 3个数的和减去 target 的差的绝对值来求最接近 target 的数。

/*
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
*/
public class Solution {
     public static int threeSumClosest(int[] nums, int target) {
        int result=Integer.MAX_VALUE;//用来保存当前最接近target的值
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++)
        {
            int temp=find(nums,i+1,nums.length-1,target,nums[i]);
            if(i==0)
            {
                result=temp;
                continue;
            }
            if(Math.abs(temp-target)<Math.abs(result-target))
            {
                result=temp;
            }
        }
        return result;
    }

    public static int find(int[] nums,int start,int end,int target,int curV)
    {
        int result=Integer.MAX_VALUE;
        int l=start,r=end;
        int c=Integer.MAX_VALUE;
        while(l<r&&c!=0)
        {
            if(Math.abs(curV+nums[l]+nums[r]-target)<c)
            {
                result =curV+nums[l]+nums[r];
                c=Math.abs(curV+nums[l]+nums[r]-target);
            }
            if(curV+nums[l]+nums[r]>target)
            {
                r--;
            }else
            {
                l++;
            }
        }
        return result;
    }
}

4 Sum 问题

4 Sum问题也显而易见了,就是求 4 个数的和等于target,那么我们可以如法炮制,前面的3 Sum我们是固定一个数,然后求两个数的和,将其分解为 2 Sum + 1 Sum,呢么 4 Sum 我们可以同样的先固定两个数,与另外两个活动的数相加等于target,也就输 4 Sum=3 Sum+1Sum。再在3 Sum的基础上嵌套一层循环就可以达到目的了,时间复杂度也降低为了O(n^3)。

/*
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note: The solution set must not contain duplicate quadruplets.

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]
*/
public class Solution {
    public static List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res=new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length-3;i++)//固定第一个数
        {
            if(i>0&&nums[i]==nums[i-1])//跳过相同的数
            {
                continue;
            }
            for(int j=i+1;j<nums.length-2;j++)//固定第二个数
            {
                if(j>i+1&&nums[j]==nums[j-1])//跳过相同的数
                {
                    continue;
                }
                find(nums,res,j+1,nums.length-1,target,nums[i],nums[j]);
            }
        }
        return res;
    }
    public static void find(int[] nums,List<List<Integer>> res,int start,int end,int target,int v1,int v2)
    {
        int l=start,r=end;
        while(l<r)
        {
            if(nums[l]+nums[r]+v1+v2==target)
            {
                List<Integer> list=new ArrayList<>();
                list.add(nums[l]);
                list.add(nums[r]);
                list.add(v1);
                list.add(v2);
                res.add(list);
                while(l<r&&nums[l]==nums[l+1])
                {
                   l++;
                }
                while(l<r&&nums[r]==nums[r-1])
                {
                   r--;
                }
                l++;
                r--;
            }else if(nums[l]+nums[r]+v1+v2<target)
            {
                l++;
            }else
            {
                r--;
            }
        }
    }
    
}

总结

做了 30 多到题,发现一个规律,如果排序后不使用二分查找或者双指针利用排序特性的话,那么排序书没有意义的,同时利用 Hash 特性也可以在增大空间复杂的同时减小时间复杂度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,712评论 0 33
  • 最近刷题发现k sum问题是非常经典的一种题型,看过别人代码后,总结求解k sum问题的通常思路。文章参考知乎le...
    BeLLESS阅读 1,715评论 0 0
  • LeetCode 刷题随手记 - 第一部分 前 256 题(非会员),仅算法题,的吐槽 https://leetc...
    蕾娜漢默阅读 17,386评论 2 36
  • 主食:烧烤,涮锅一体 价位:98元每位,支持团购 位置:领先市场电影院6层 店面:四人桌,六人桌,包间12人 桌 ...
    可苦可乐21314阅读 350评论 0 0
  • 子曰:自天子以至于庶人,壹是以修身为本。 金无赤足,人无完人。克己修身的深度很大程度上决定了一个人取得成就的高度。...
    坚冰至_Monsol阅读 885评论 0 6