6269. Shortest Distance to Target String in a Circular Array

给你一个下标从 0 开始的 环形 字符串数组 words 和一个字符串 target 。环形数组 意味着数组首尾相连。

形式上, words[i] 的下一个元素是 words[(i + 1) % n] ,而 words[i] 的前一个元素是 words[(i - 1 + n) % n] ,其中 n 是 words 的长度。
从 startIndex 开始,你一次可以用 1 步移动到下一个或者前一个单词。

返回到达目标字符串 target 所需的最短距离。如果 words 中不存在字符串 target ,返回 -1 。

测试样例
输入:words = ["hello","i","am","leetcode","hello"], target = "hello", startIndex = 1
输出:1

解释:从下标 1 开始,可以经由以下步骤到达 "hello" :

  • 向右移动 3 个单位,到达下标 4 。
  • 向左移动 2 个单位,到达下标 4 。
  • 向右移动 4 个单位,到达下标 0 。
  • 向左移动 1 个单位,到达下标 0 。
    到达 "hello" 的最短距离是 1 。

解答: 按照题意计算距离,注意循环队列问题。

class Solution {
    public int closetTarget(String[] words, String target, int startIndex) {
        List<Integer> pos = new ArrayList<>();
        for (int i = 0; i < words.length; ++i) {
            if (words[i].equals(target)) {
                pos.add(i);
            }
        }
        if (!pos.isEmpty()) {
            int res = Integer.MAX_VALUE;
            for (int i : pos) {
                res = Math.min(res, Math.abs(i - startIndex));
                if (i < startIndex) {
                    res = Math.min(res, words.length - startIndex + i);
                } else {
                    res = Math.min(res, startIndex + words.length - i);
                }
            }
            return res;
        }
        return -1;
    }
}

6270. Take K of Each Character From Left and Right

给你一个由字符 'a'、'b'、'c' 组成的字符串 s 和一个非负整数 k 。每分钟,你可以选择取走 s 最左侧 还是 最右侧 的那个字符。

你必须取走每种字符 至少 k 个,返回需要的 最少 分钟数;如果无法取到,则返回 -1 。

测试样例
输入:s = "aabaaaacaabc", k = 2
输出:8

解释:
从 s 的左侧取三个字符,现在共取到两个字符 'a' 、一个字符 'b' 。
从 s 的右侧取五个字符,现在共取到四个字符 'a' 、两个字符 'b' 和两个字符 'c' 。
共需要 3 + 5 = 8 分钟。
可以证明需要的最少分钟数是 8 。

解答:队列左右2边进行双指针计算。

class Solution {
    public int takeCharacters(String s, int k) {
        int[] count = new int[3];
        for (int i = 0; i < s.length(); ++i) {
            count[s.charAt(i) - 'a'] += 1;
        }
        if (count[0] < k || count[1] < k || count[2] < k) {
            return -1;
        }
        int res = s.length();
        int r = s.length();
        for (int i = s.length() - 1; i >= -1; --i) {
            while (count[0] < k || count[1] < k || count[2] < k) {
                --r;
                count[s.charAt(r) - 'a'] += 1;
            }
            res = Math.min(res, i + 1 + s.length() - r);
            if (i >= 0) count[s.charAt(i) - 'a'] -= 1;
        }
        return res;
    }
}

6271. Maximum Tastiness of Candy Basket

给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k 。

商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。

返回礼盒的 最大 甜蜜度。

测试样例:
输入:price = [13,5,1,8,21,2], k = 3

输出:8

解释:选出价格分别为 [13,5,21] 的三类糖果。
礼盒的甜蜜度为 min(|13 - 5|, |13 - 21|, |5 - 21|) = min(8, 8, 16) = 8 。
可以证明能够取得的最大甜蜜度就是 8 。

解答: 排序+二分查找

class Solution {
    public int maximumTastiness(int[] price, int k) {
        Arrays.sort(price);
        int min = 0, max = price[price.length - 1] - price[0] + 1;
        while (min < max) {
            int mid = min + (max - min + 1) / 2;
            int last = price[0], count = 1;
            for (int i : price) {
                if (i - last >= mid) {
                    last = i;
                    ++count;
                }
            }
            if (count >= k) {
                min = mid;
            } else {
                max = mid - 1;
            }
        }
        return min;
    }
}

6272. Number of Great Partitions

给你一个正整数数组 nums 和一个整数 k 。

分区 的定义是:将数组划分成两个有序的 组 ,并满足每个元素 恰好 存在于 某一个 组中。如果分区中每个组的元素和都大于等于 k ,则认为分区是一个好分区。

返回 不同 的好分区的数目。由于答案可能很大,请返回对 109 + 7 取余 后的结果。

如果在两个分区中,存在某个元素 nums[i] 被分在不同的组中,则认为这两个分区不同。

测试样例
输入:nums = [1,2,3,4], k = 4

输出:6

解释:好分区的情况是 ([1,2,3], [4]), ([1,3], [2,4]), ([1,4], [2,3]), ([2,3], [1,4]), ([2,4], [1,3]) 和 ([4], [1,2,3]) 。

解答:这道题目真的阅读理解,完全没理解这个有序组的含义。。。实际就是简单的动态规划。反向思维,计算所有可能,然后排出不可能的组合。代码仅供参考,如果判断sum不符合条件的情况,计算会出错。总觉得哪里还有bug。

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

    public int countPartitions(int[] nums, int k) {
        if (!isValid(nums, k)) {
            return 0;
        }
        int res = 1;
        for (int i = 0; i < nums.length; ++i) {
            res = res * 2 % mod;
        }

        int[] count = new int[k];
        count[0] = 1;
        for (int i : nums) {
            for (int j = k - 1; j >= i; --j) {
                count[j] = (count[j] + count[j - i]) % mod;
            }
        }
        for (int i : count) {
            res = (res + mod - (i * 2 % mod)) % mod;
        }
        return res;
    }

    private boolean isValid(int[] nums, int k) {
        long sum = 0;
        for (int i : nums) {
            sum += i;
        }
        return nums.length > 1 && sum >= k * 2;
    }
}

Leave a Reply

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