LeetCode 101双周赛


2605. 从两个数字数组里生成最小数字

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

示例 1:

输入:nums1 = [4,1,3], nums2 = [5,7]
输出:15
解释:数字 15 的数位 1 在 nums1 中出现,数位 5 在 nums2 中出现。15 是我们能得到的最小数字。
示例 2:

输入:nums1 = [3,5,2,6], nums2 = [3,1,7]
输出:3
解释:数字 3 的数位 3 在两个数组中都出现了。
 

提示:

1 <= nums1.length, nums2.length <= 9
1 <= nums1[i], nums2[i] <= 9
每个数组中,元素 互不相同 。

解答:直接用两个set+排序

class Solution {
    public int minNumber(int[] nums1, int[] nums2) {
           Set<Integer> set1=new HashSet<>();
           Set<Integer> set2=new HashSet<>();
           for(int n:nums1)set1.add(n);
           for(int n:nums2)set2.add(n);
           int res=100000;
           for(int n:nums1){
               if(set2.contains(n))res=Math.min(res,n);
           }
           Arrays.sort(nums1);
           Arrays.sort(nums2);
           int a=nums1[0],b=nums2[0];
           if(a<b)res=Math.min(res,a*10+b);
           else res=Math.min(res,b*10+a);
           return  res;
    }
    
}

2606. 找到最大开销的子字符串

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

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

字符的价值 定义如下:

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

 

示例 1:

输入:s = "adaa", chars = "d", vals = [-1000]
输出:2
解释:字符 "a""d" 的价值分别为 1-1000 。
最大开销子字符串是 "aa" ,它的开销为 1 + 1 = 22 是最大开销。
示例 2:

输入:s = "abc", chars = "abc", vals = [-1,-1,-1]
输出:0
解释:字符 "a""b""c" 的价值分别为 -1 ,-1 和 -1 。
最大开销子字符串是 "" ,它的开销为 00 是最大开销。
 

提示:

1 <= s.length <= 10^5
s 只包含小写英文字母。
1 <= chars.length <= 26
chars 只包含小写英文字母,且 互不相同 。
vals.length == chars.length
-1000 <= vals[i] <= 1000

解答:Set+贪心

class Solution {
    public int maximumCostSubstring(String s, String chars, int[] vals) {
        int[] res=new int[26];
        Set<Integer> set=new HashSet<>();
        for(int i=0;i<chars.length();i++){
            char c=chars.charAt(i);
            res[c-'a']=vals[i];
            set.add(c-'a');
        }
        for(int i=0;i<26;i++){
            if(set.contains(i))continue;
            else res[i]=i+1;
        }
        int ans=0;
        int sum=0;
        for (int i=0;i<s.length();i++){
            if(sum<=0)sum=0;
            char c=s.charAt(i);
            sum+=res[c-'a'];
            ans=Math.max(ans,sum);
        }
        return ans;
    }
}

6351. 标记所有元素后数组的分数

给你一个数组 nums ,它包含若干正整数。

一开始分数 score = 0 ,请你按照下面算法求出最后分数:

从数组中选择最小且没有被标记的整数。如果有相等元素,选择下标最小的一个。
将选中的整数加到 score 中。
标记 被选中元素,如果有相邻元素,则同时标记 与它相邻的两个元素 。
重复此过程直到数组中所有元素都被标记。
请你返回执行上述算法后最后的分数。

 

示例 1:

输入:nums = [2,1,3,4,5,2]
输出:7
解释:我们按照如下步骤标记元素:
- 1 是最小未标记元素,所以标记它和相邻两个元素:[2,1,3,4,5,2] 。
- 2 是最小未标记元素,所以标记它和左边相邻元素:[2,1,3,4,5,2] 。
- 4 是仅剩唯一未标记的元素,所以我们标记它:[2,1,3,4,5,2] 。
总得分为 1 + 2 + 4 = 7 。
示例 2:

输入:nums = [2,3,5,1,3,2]
输出:5
解释:我们按照如下步骤标记元素:
- 1 是最小未标记元素,所以标记它和相邻两个元素:[2,3,5,1,3,2] 。
- 2 是最小未标记元素,由于有两个 2 ,我们选择最左边的一个 2 ,也就是下标为 0 处的 2 ,以及它右边相邻的元素:[2,3,5,1,3,2] 。
- 2 是仅剩唯一未标记的元素,所以我们标记它:[2,3,5,1,3,2] 。
总得分为 1 + 2 + 2 = 5 。
 

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6

解答:中位数贪心+裴蜀定理

class Solution {
    public long makeSubKSumEqual(int[] arr, int k) {
        int n = arr.length;
        k = gcd(k, n);
        long ans = 0;
        for (int i = 0; i < k; ++i) {
            var b = new ArrayList<Integer>();
            for (int j = i; j < n; j += k)
                b.add(arr[j]);
            Collections.sort(b);
            int mid = b.get(b.size() / 2);
            for (int x : b)
                ans += Math.abs(x - mid);
        }
        return ans;
    }

    private int gcd(int a, int b) {
        return b==0?a:gcd(b,a%b);
    }
}

2608. 图中的最短环

现有一个含 n 个顶点的 双向 图,每个顶点按从 0 到 n - 1 标记。图中的边由二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和 vi 之间存在一条边。每对顶点最多通过一条边连接,并且不存在与自身相连的顶点。
返回图中 最短 环的长度。如果不存在环,则返回 -1 。
环 是指以同一节点开始和结束,并且路径中的每条边仅使用一次。

示例 1:

输入:n = 7, edges = [[0,1],[1,2],[2,0],[3,4],[4,5],[5,6],[6,3]]
输出:3
解释:长度最小的循环是:0 -> 1 -> 2 -> 0 
示例 2:


输入:n = 4, edges = [[0,1],[0,2]]
输出:-1
解释:图中不存在循环
 

提示:
2 <= n <= 1000
1 <= edges.length <= 1000
edges[i].length == 2
0 <= ui, vi < n
ui != vi
不存在重复的边

解答:BFS

class Solution {
    public int findShortestCycle(int n, int[][] edges) {
        List<List<Integer>> adj = new ArrayList<>(); // 邻接表
        for (int i = 0; i < n; i++) {
            adj.add(new ArrayList<>());
        }
        for (int[] edge : edges) {
            int u = edge[0], v = edge[1];
            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        int shortestCycle = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            Queue<Integer> queue = new LinkedList<>();
            int[] dist = new int[n];
            Arrays.fill(dist, -1);
            dist[i] = 0;
            queue.offer(i);
            while (!queue.isEmpty()) {
                int u = queue.poll();
                for (int v : adj.get(u)) {
                    if (dist[v] == -1) {
                        dist[v] = dist[u] + 1;
                        queue.offer(v);
                    } else if (v != i && v != u && dist[v] >= dist[u]) {
                        shortestCycle = Math.min(shortestCycle, dist[u] + dist[v] + 1);
                    }
                }
            }
        }

        return shortestCycle == Integer.MAX_VALUE ? -1 : shortestCycle;
    }
}

  目录