6327. Form Smallest Number From Two Digit Arrays

给你两个只包含 1 到 9 之间数字的数组 nums1 和 nums2 ,每个数组中的元素 互不相同 ,请你返回 最小 的数字,两个数组都 至少 包含这个数字的某个数位。

测试样例

输入:nums1 = [4,1,3], nums2 = [5,7]

输出:15

解释:

数字 15 的数位 1 在 nums1 中出现,数位 5 在 nums2 中出现。15 是我们能得到的最小数字。

没有分配方案能让获得 8 美元的儿童数超过 1 。

解答:如果2个数组有一样的数字,则返回最小的相同数字。否则就分别挑选2个数组的最小值,然后返回一个十位数。

class Solution {
    public int minNumber(int[] nums1, int[] nums2) {
        Set<Integer> set = new HashSet<>();
        int min2 = Integer.MAX_VALUE;
        for (int n : nums2) {
            set.add(n);
            min2 = Math.min(n, min2);
        }
        int min1 = Integer.MAX_VALUE, common = Integer.MAX_VALUE;
        for (int n : nums1) {
            if (set.contains(n)) {
                common = Math.min(common, n);
            }
            min1 = Math.min(min1, n);
        }
        if (common != Integer.MAX_VALUE) {
            return common;
        }
        return Math.min(min1, min2) * 10 + Math.max(min1, min2);
    }
}

6328. Find the Substring With Maximum Cost

给你一个字符串 s ,一个字符 互不相同 的字符串 chars 和一个长度与 chars 相同的整数数组 vals 。

子字符串的开销 是一个子字符串中所有字符对应价值之和。空字符串的开销是 0 。

字符的价值 定义如下:

  • 如果字符不在字符串 chars 中,那么它的价值是它在字母表中的位置(下标从 1 开始)。
    • 比方说,'a' 的价值为 1 ,'b' 的价值为 2 ,以此类推,'z' 的价值为 26 。
  • 否则,如果这个字符在 chars 中的位置为 i ,那么它的价值就是 vals[i]。

请你返回字符串 s 的所有子字符串中的最大开销。

测试样例:

输入:s = "adaa", chars = "d", vals = [-1000]

输出:2

解释:

字符 "a" 和 "d" 的价值分别为 1 和 -1000 。最大开销子字符串是 "aa" ,它的开销为 1 + 1 = 2 。2 是最大开销。

解答: 本质就是最大子数组和

class Solution {
    public int maximumCostSubstring(String s, String chars, int[] vals) {
        int[] map = new int[26];
        for (int i = 0; i < 26; ++i) {
            map[i] = i + 1;
        }
        for (int i = 0; i < chars.length(); ++i) {
            map[chars.charAt(i) - 'a'] = vals[i];
        }
        int max = 0, sum = 0;
        for (int i = 0; i < s.length(); ++i) {
            sum += map[s.charAt(i) - 'a'];
            max = Math.max(max, sum);
            sum = Math.max(0, sum);
        }
        return max;
    }
}

6329. Make K-Subarray Sums Equal

给你一个下标从 0 开始的整数数组 arr 和一个整数 k 。数组 arr 是一个循环数组。换句话说,数组中的最后一个元素的下一个元素是数组中的第一个元素,数组中第一个元素的前一个元素是数组中的最后一个元素。

你可以执行下述运算任意次:

  • 选中 arr 中任意一个元素,并使其值加上 1 或减去 1 。

执行运算使每个长度为 k 的 子数组 的元素总和都相等,返回所需要的最少运算次数。

子数组 是数组的一个连续部分。

测试样例:

输入:arr = [1,4,1,3], k = 2

输出:1

解释:

在下标为 1 的元素那里执行一次运算,使其等于 3 。

执行运算后,数组变为 [1,3,1,3] 。

  • 0 处起始的子数组为 [1, 3] ,元素总和为 4
  • 1 处起始的子数组为 [3, 1] ,元素总和为 4
  • 2 处起始的子数组为 [1, 3] ,元素总和为 4
  • 3 处起始的子数组为 [3, 1] ,元素总和为 4

解答: 由于数组是循环数组,且所有长度为k的子数组总和一定要一样。那么我们可以知道arr[i] == arr[(i + k) % arr.length]。这样用并查集将所有应该一样的数字聚合,然后利用中位数寻找产生的操作数。

class Solution {
    private class DSU {
        private int[] parent;

        public DSU(int n) {
            parent = new int[n];
            for (int i = 0; i < n; ++i) {
                parent[i] = i;
            }
        }

        public int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }

        public void union(int x, int y) {
            parent[find(x)] = find(y);
        }
    }

    public long makeSubKSumEqual(int[] arr, int k) {
        DSU uf = new DSU(arr.length);
        for (int i = 0; i < arr.length; ++i) {
            uf.union(i, (i + k) % arr.length);
        }
        Map<Integer, List<Integer>> group = new HashMap<>();
        for (int i = 0; i < arr.length; ++i) {
            int p = uf.find(i);
            if (!group.containsKey(p)) {
                group.put(p, new ArrayList<>());
            }
            group.get(p).add(arr[i]);
        }
        long res = 0;
        for (Map.Entry<Integer, List<Integer>> kv : group.entrySet()) {
            res += helper(kv.getValue());
        }
        return res;
    }

    private long helper(List<Integer> list) {
        Collections.sort(list);
        int mid = list.get(list.size() / 2);
        long res = 0;
        for (int i : list) {
            res += Math.abs(i - mid);
        }
        return res;
    }
}

6330. Shortest Cycle in a Graph

现有一个含 n 个顶点的 双向 图,每个顶点按从 0 到 n - 1 标记。图中的边由二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和 vi 之间存在一条边。每对顶点最多通过一条边连接,并且不存在与自身相连的顶点。

返回图中 最短 环的长度。如果不存在环,则返回 -1 。

环 是指以同一节点开始和结束,并且路径中的每条边仅使用一次。

测试样例:

输入:n = 7, edges = [[0,1],[1,2],[2,0],[3,4],[4,5],[5,6],[6,3]]

输出:3

解释:

长度最小的循环是:0 -> 1 -> 2 -> 0

解答:这道题目有2个很重要的提示:

  • 2 <= n <= 1000
  • 1 <= edges.length <= 1000

这个规模可以直接利用暴力计算每个节点为开始的最小环(如果存在环的话)。

class Solution {
    public int findShortestCycle(int n, int[][] _edges) {
        List<Integer>[] edges = new List[n];
        for (int i = 0; i < n; ++i) {
            edges[i] = new ArrayList<>();
        }
        for (int[] e : _edges) {
            edges[e[0]].add(e[1]);
            edges[e[1]].add(e[0]);
        }
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < n; ++i) {
            Queue<int[]> queue = new LinkedList<>();
            queue.add(new int[]{i, -1}); queue.add(null);
            int[] isVisited = new int[n];
            Arrays.fill(isVisited, -1);
            isVisited[i] = 0;
            int dis = 1;

            while (queue.size() > 1) {
                int[] tmp = queue.poll();
                if (tmp == null) {
                    queue.add(null);
                    ++dis;
                } else {
                    for (int next : edges[tmp[0]]) {
                        if (isVisited[next] == -1) {
                            isVisited[next] = dis;
                            queue.add(new int[]{next, tmp[0]});
                        } else if (next != tmp[1]) {
                            min = Math.min(min, isVisited[next] + isVisited[tmp[0]] + 1);
                        }
                    }
                }
            }
        }
        return min == Integer.MAX_VALUE ? -1 : min;
    }
}

Leave a Reply

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