欢迎大家加QQ群:623375442,可以方便群里面交流。

100452. Minimum Element After Replacement With Digit Sum

给你一个整数数组 nums 。

请你将 nums 中每一个元素都替换为它的各个数位之 和 。

请你返回替换所有元素以后 nums 中的 最小 元素。

测试样例:

输入:nums = [10,12,13,14]

输出:1

解释:nums 替换后变为 [1, 3, 4, 5] ,最小元素为 1 。

解答:按照题意暴力计算。

class Solution {
    public int minElement(int[] nums) {
        int res = Integer.MAX_VALUE;
        for (int n : nums) {
            int digit = 0;
            while (n > 0) {
                digit += n % 10;
                n /= 10;
            }
            res = Math.min(res, digit);
        }
        return res;
    }
}

100374. Maximize the Total Height of Unique Towers

给你一个数组 maximumHeight ,其中 maximumHeight[i] 表示第 i 座塔可以达到的 最大 高度。

你的任务是给每一座塔分别设置一个高度,使得:

  1. 第 i 座塔的高度是一个正整数,且不超过 maximumHeight[i] 。
  2. 所有塔的高度互不相同。
    请你返回设置完所有塔的高度后,可以达到的 最大 总高度。如果没有合法的设置,返回 -1 。

返回 result 。

测试样例:

输入:maximumHeight = [2,3,4,3]

输出:10

解释:
我们可以将塔的高度设置为:[1, 2, 4, 3] 。

解答:利用贪婪计算。

class Solution {
    public long maximumTotalSum(int[] maximumHeight) {
        Arrays.sort(maximumHeight);
        long res = 0, cur = Long.MAX_VALUE;
        for (int i = maximumHeight.length - 1; i >= 0; --i) {
            if (maximumHeight[i] <= cur) {
                res += maximumHeight[i];
                cur = maximumHeight[i] - 1;
            } else {
                if (cur <= 0) {
                    return -1;
                }
                res += cur;
                cur -= 1;
            }
        }
        return res;
    }
}

100437. Find the Lexicographically Smallest Valid Sequence

给你两个字符串 word1 和 word2 。

如果一个字符串 x 修改 至多 一个字符会变成 y ,那么我们称它与 y 几乎相等 。

如果一个下标序列 seq 满足以下条件,我们称它是 合法的 :

  • 下标序列是 升序 的。
  • 将 word1 中这些下标对应的字符 按顺序 连接,得到一个与 word2 几乎相等 的字符串。

请你返回一个长度为 word2.length 的数组,表示一个 字典序最小 的 合法 下标序列。如果不存在这样的序列,请你返回一个 空 数组。

注意 ,答案数组必须是字典序最小的下标数组,而 不是 由这些下标连接形成的字符串。

测试样例:

输入:word1 = "vbcca", word2 = "abc"

输出:[0,1,2]

解释:字典序最小的合法下标序列为 [0, 1, 2] :

  • 将 word1[0] 变为 'a' 。
  • word1[1] 已经是 'b' 。
  • word1[2] 已经是 'c' 。

解答:我觉得这周最难的就是这题。我们先从后遍历word2,寻找能满足word2后缀匹配的最大word1距离。然后正向计算最小的更换一次的结果。

class Solution {
    private static final int[] failed = {};

    public int[] validSequence(String word1, String word2) {
        TreeSet<Integer>[] sets = new TreeSet[26];
        for (int i = 0; i < 26; ++i) {
            sets[i] = new TreeSet<>();
        }
        for (int i = 0; i < word1.length(); ++i) {
            sets[word1.charAt(i) - 'a'].add(i);
        }
        int[] minLeft = new int[word2.length() + 1];
        Arrays.fill(minLeft, -1);
        minLeft[word2.length()] = word1.length();
        for (int i = word2.length() - 1; i >= 0; --i) {
            // 从后向前寻找能够匹配word2后缀的最大word1的位置
            int o = word2.charAt(i) - 'a';
            Integer tmp = sets[o].lower(minLeft[i + 1]);
            if (tmp == null) {
                break;
            }
            minLeft[i] = tmp;
        }

        int last = -1;
        int[] res = new int[word2.length()];
        // 正向计算
        for (int i = 0; i < word2.length(); ++i) {
            Integer tmp = sets[word2.charAt(i) - 'a'].higher(last);
            // 如果当前位置就是可以匹配的,直接继续。
            if (tmp != null && tmp == last + 1) {
                res[i] = tmp;
                last = tmp;
            } else if (minLeft[i + 1] > i && minLeft[i + 1] > last + 1) {
                for (int j = i; j < word2.length(); ++j) {
                    if (j != i) {
                        res[j] = sets[word2.charAt(j) - 'a'].higher(res[j - 1]);
                    } else {
                        res[j] = last + 1;
                    }
                }
                return res;
            } else {
                if (tmp == null) {
                    break;
                }
                res[i] = tmp;
                last = tmp;
            }
        }
        if (word1.startsWith(word2)) {
            return res;
        }
        return failed;
    }
}

100433. Find the Occurrence of First Almost Equal Substring

给你两个字符串 s 和 pattern 。

如果一个字符串 x 修改 至多 一个字符会变成 y ,那么我们称它与 y 几乎相等 。

请你返回 s 中下标 最小 的 子字符串 ,它与 pattern 几乎相等 。如果不存在,返回 -1 。

子字符串 是字符串中的一个 非空、连续的字符序列。

测试样例:

输入:s = "abcdefg", pattern = "bcdffg"

输出:1

解释:
将子字符串 s[1..6] == "bcdefg" 中 s[4] 变为 "f" ,得到 "bcdffg" 。

解答:利用Rolling Hash,寻找每个位置可以匹配的最大位置,然后查看剩下的位置是否能够匹配上。

class Solution {
    private static final int mod = 1_000_000_007;
    private static final int inv = 129032259;

    private class RangeHash {
        long[] prefix, div;

        public RangeHash(String word) {
            prefix = new long[word.length() + 1];
            div = new long[word.length() + 1];
            long mul = 1;
            div[0] = 1;
            for (int i = 0; i < word.length(); ++i) {
                int t = word.charAt(i) - 'a';
                prefix[i + 1] = (prefix[i] + t * mul) % mod;
                mul = (mul * 31) % mod;
                div[i + 1] = div[i] * inv % mod;
            }
        }

        public long getRangeHash(int st, int ed) {
            long diff = (prefix[ed + 1] - prefix[st] + mod) % mod;
            return diff * div[st] % mod;
        }
    }

    public int minStartingIndex(String s, String pattern) {
        if (pattern.length() <= 1) {
            return 0;
        }
        RangeHash sh = new RangeHash(s), ph = new RangeHash(pattern);
        for (int i = 0; i <= s.length() - pattern.length(); ++i) {
            int st = 0, ed = pattern.length() - 1;
            // 折半搜索当前位置最大可以匹配的距离
            while (st < ed) {
                int mid = (st + ed) / 2;
                if (sh.getRangeHash(i, i + mid) == ph.getRangeHash(0, mid)) {
                    st = mid + 1;
                } else {
                    ed = mid;
                }
            }
            if (st >= pattern.length() - 1) {
                return i;
            // 利用Rolling Hash快速计算一下剩下的位置是不是正确
            } else if (ph.getRangeHash(st + 1, pattern.length() - 1)
                    == sh.getRangeHash(i + st + 1, i + pattern.length() - 1)) {
                return i;
            }
        }
        return -1;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *