程序员老鬼

刚升小组长,下属比我年纪还大,怎么管?上个月刚被提成小组长,手下3个人,两个比我大3岁,一个还是老员工。

刚看到个贴子,说一网友刚升小组长,下面三个人俩比他大,还有一个老员工。安排任务老感觉对方不太当回事,开会也不说话,就纠结要不要请客吃饭,还是直接立规矩。

Image

我觉得这事吧,先别纠结“我比他们小”,职场看的是角色和价值,不是辈分。有篇文章就说过,职场第一准则是价值,而不是努力。你现在的“价值”,就是把活儿带好,让大家跟着你把结果做出来。

我比较认同“先把事说明白,再谈感情”。先开个小范围会议,把目标、分工、决策方式讲清楚,让大家知道你是来解决问题的,不是来当哥们的。之后再一对一聊聊,听听老员工的想法,给足尊重。饭可以吃,但别指望一顿饭解决管理问题。

面试题:匹配子序列的单词数

昨天晚上快十一点,我在公司楼下等外卖,手机一刷,群里一个实习生跟我说:“哥,四数之和这道题我写了一下午,还是一团浆糊,你有空讲讲不?”我一看,这不就是经典面试题嘛,用 Java 写也不难,就是容易写成一坨 n⁴ 的屎山代码。

我先把题目翻成人话啊:给你一个 int 数组 nums,再给一个目标值 target,让你找出所有“四个数的组合”,这四个数加起来正好等于 target,而且组合不能重复,比如 [-2,-1,1,2] 和 [-1,-2,1,2] 算一个。

很多人第一反应是四层 for 循环,把所有四元组都枚举一遍,时间复杂度 O(n⁴),数组长一点就寄了。

正常一点的玩法是这样的:

  1. 先排序:Arrays.sort(nums)排完序之后,有个好处是——去重就好搞了,双指针也能用上。

  2. 外面两层 for 固定前两个数 i、j

  • 第一层 i 从 0 到 n-4
  • 第二层 j 从 i+1 到 n-3
  • 里面一对双指针算“剩下两数之和”

    • 左指针 l = j + 1,右指针 r = n - 1
    • 当前和 sum = nums[i] + nums[j] + nums[l] + nums[r]
    • 如果 sum == target,记录一组
    • sum < target,说明太小,l++
    • sum > target,说明太大,r--
  • 去重很关键,不然结果一堆重复

    • while(l < r && nums[l] == nums[l+1]) l++;
    • while(l < r && nums[r] == nums[r-1]) r--;
    • 然后再 l++,r-- 开始下一轮
    • i 这一层:if(i > 0 && nums[i] == nums[i-1]) continue;

    • j 这一层:if(j > i+1 && nums[j] == nums[j-1]) continue;

    • 找到一组解之后:

    核心就是:外面两层枚举 + 里面两数之和,整体复杂度 O(n³),这在面试题里是完全能接受的。

    直接给你一份能跑的写法,注意几个小细节我都写在注释里了:

    import java.util.*;

    publicclassFourSumSolution{

    public List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> res = new ArrayList<>();
    if (nums == null || nums.length < 4) {
    return res;
            }

            Arrays.sort(nums);
    int n = nums.length;

    for (int i = 0; i < n - 3; i++) {
    // 第一层去重
    if (i > 0 && nums[i] == nums[i - 1]) {
    continue;
                }

    for (int j = i + 1; j < n - 2; j++) {
    // 第二层去重
    if (j > i + 1 && nums[j] == nums[j - 1]) {
    continue;
                    }

    int left = j + 1;
    int right = n - 1;

    while (left < right) {
    // 防止溢出,先转成 long
    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];

    if (sum == target) {
                            res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));

    // 左右指针去重
    while (left < right && nums[left] == nums[left + 1]) {
                                left++;
                            }
    while (left < right && nums[right] == nums[right - 1]) {
                                right--;
                            }

                            left++;
                            right--;
                        } elseif (sum < target) {
                            left++;
                        } else {
                            right--;
                        }
                    }
                }
            }

    return res;
        }
    }

    你自己写的时候,最容易翻车的三个点,我顺嘴提醒一下:

    • 忘记排序:不排序去重会非常难受,还不好用双指针。
    • 去重条件写错:特别是 j > i + 1 这个地方,少写个加一,就会漏掉首个合法组合或者多算。
    • int 溢出:数据范围一大,nums[i] + nums[j] + ... 直接炸,所以我用的是 long sum。

    比如最经典的这个:

    nums = [1, 0, -1, 0, -2, 2], target = 0

    排序之后是 [-2, -1, 0, 0, 1, 2],你心里就有数了,答案应该是:

    • [-2, -1, 1, 2]
    • [-2, 0, 0, 2]
    • [-1, 0, 0, 1]

    代码跑出来也会是这三个,顺序可能不一样,但没关系,面试官一般不管顺序。

    复杂度简单说一下: 外面两层 for 是 O(n²),里面双指针一圈是 O(n),所以总的就是 O(n³)。空间上只用了结果列表,算 O(1) 额外空间。

    差不多就这样,你可以先照着敲一遍,自己打几个用例跑一跑,熟悉一下指针的移动节奏。下次有人问你“四数之和”,你就可以像装模作样地说一句:“这个题啊,很经典的排序加双指针变形题”。我这边先去冲杯咖啡,等会还得改需求😅。

    -END-

    我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html