8/10, Google Tag

挺简单的,和 group anagram 异曲同工。

唯一需要注意的就是 "az" 和 "ba" 同组,说明字母表是环形的。两个字母之间的差如果为负数,就把 diff 加上 26. "az" diff = -25 + 26 = 1; "ba" diff = 1;

public class Solution {
    public List<List<String>> groupStrings(String[] strings) {
        List<List<String>> rst = new ArrayList<>();
        // Key : diff1,diff2... single character is "" 
        // Value : list of strings grouped together
        HashMap<String, List<String>> map = new HashMap<>();
        StringBuilder sb = new StringBuilder();

        for(int i = 0 ; i < strings.length; i++){
            String str = strings[i];
            sb.setLength(0);
            for(int j = 0; j < str.length() - 1; j++){
                int diff = str.charAt(j) - str.charAt(j + 1);
                if(diff < 0) diff += 26;
                sb.append(diff);
                sb.append(',');
            }
            String key = sb.toString();
            if(!map.containsKey(key)) map.put(key, new ArrayList<String>());
            map.get(key).add(str);
        }

        Iterator<String> iter = map.keySet().iterator();
        while(iter.hasNext()){
            rst.add(map.get(iter.next()));
        }

        return rst;
    }
}

一开始看错了,以为是相乘,搞了一堆因式分解数因数的。。还往数论上想了半天。

后来发现 BFS 就能 AC.

前两次提交都在大数上 MLE,说明 BFS 剪枝不到位。

  • 扫合理 moves 的时候,先从大的扫;

  • 用个 hashset 存一下已经访问过的 sum 值,避免重复;

以上两招都可以很简便的减少内存和计算时间开销。

再仔细观察一下这题:

  • 我们要凑出来一个和正好是 n 的选择组合;

  • 能选的元素是固定数量的 perfect square (有的会超)

  • 一个元素可以选多次;

这就是背包啊!

流程:

  • start 从倒数第二个数起,往左扫,寻找到第一个 nums[start] < nums[start + 1] 的位置;

  • 从 start 往后找,找到第一个比 nums[start] 小的前一个数 (也就是最小的大于等于 nums[start] 的数)

  • 交换 start , end

  • 把 start + 1 后面的区间翻转,over.

1: 右往左,找下落;

2:左往右,找 threshold (换过来的数,怎么说也得比 nums[start] 大)

3:交换,反转。

为什么一个这么简单的 DFS 能超过 89% ..

注意:index == 0 并且 i == 0 的时候要跳过,免得在起始位置填上 0 .

Google 面经里的 follow-up 是,给定一个上限 n ,输出所有上限范围内的数。

办法土了点,遍历所有 lowLen ~ highLen 区间的长度,生成所有可能的结果,考虑到区间可能是大数,我们就改一下,自己写一个 String compare 函数好了。

后来发现有点多余,可以直接用内置的 str1.compareTo(str2).

超过 81.92% ~

我很喜欢这题,挺有创意~

  • 注意点 1 : a = 0 的时候是直线,不能无脑按照抛物线的方式处理;

  • 注意点 2 : 对称轴 -b / 2 * a 的时候括号顺序是 (double) -b / (2 * a)

第一次 AC 的代码~ 太粗糙,得改改。

这题比较简洁的写法如下,明天学习一个。

这种写法的核心是只看 a 的 “正负”,无所谓 0.

  • If a > 0; the smallest number must be at two ends of orgin array;

  • If a < 0; the largest number must be at two ends of orgin array;

  • 换句话说,a 的符号可以直接确定 two pointer 两端一定有一个 “最大/最小” 的值,每次 O(1) 计算一下就好,也能处理直线的情况。

Last updated

Was this helpful?