力扣450场周赛

3550. 数位和等于下标的最小下标

简单

给你一个整数数组 nums

返回满足 nums[i] 的数位和(每一位数字相加求和)等于 i最小 下标 i

如果不存在满足要求的下标,返回 -1

示例 1:

**输入:**nums = [1,3,2]

**输出:**2

解释:

  • nums[2] = 2,其数位和等于 2 ,与其下标 i = 2 相等。因此,输出为 2 。

示例 2:

**输入:**nums = [1,10,11]

**输出:**1

解释:

  • nums[1] = 10,其数位和等于 1 + 0 = 1,与其下标 i = 1 相等。
  • nums[2] = 11,其数位和等于是 1 + 1 = 2,与其下标 i = 2 相等。
  • 由于下标 1 是满足要求的最小下标,输出为 1 。

示例 3:

**输入:**nums = [1,2,3]

输出:-1

解释:

  • 由于不存在满足要求的下标,输出为 -1 。

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
impl Solution {
    pub fn smallest_index(nums: Vec<i32>) -> i32 {
        for (i, &num) in nums.iter().enumerate() {
            let mut t = num;
            let mut r = 0;

            while t > 0 {
                r += t % 10;
                t /= 10;
            }

            if r == i as i32 {
                return i as i32;
            }
        }
        -1
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
    public int smallestIndex(int[] nums) {
        for(int i=0;i<nums.length;i++){
            int t=nums[i],r=0;
            while(t>0){
                r+=t%10;
                t/=10;
            }
            if(r==i) return i;
        }
        return -1;
    }
}

3551. 数位和排序需要的最小交换次数

中等

给你一个由 互不相同 的正整数组成的数组 nums,需要根据每个数字的数位和(即每一位数字相加求和)按 升序 对数组进行排序。如果两个数字的数位和相等,则较小的数字排在前面。

返回将 nums 排列为上述排序顺序所需的 最小 交换次数。

一次 交换 定义为交换数组中两个不同位置的值。

示例 1:

输入: nums = [37,100]

输出: 1

解释:

  • 计算每个整数的数位和:[3 + 7 = 10, 1 + 0 + 0 = 1] → [10, 1]
  • 根据数位和排序:[100, 37]。将 37100 交换,得到排序后的数组。
  • 因此,将 nums 排列为排序顺序所需的最小交换次数为 1。

示例 2:

输入: nums = [22,14,33,7]

输出: 0

解释:

  • 计算每个整数的数位和:[2 + 2 = 4, 1 + 4 = 5, 3 + 3 = 6, 7 = 7] → [4, 5, 6, 7]
  • 根据数位和排序:[22, 14, 33, 7]。数组已经是排序好的。
  • 因此,将 nums 排列为排序顺序所需的最小交换次数为 0。

示例 3:

输入: nums = [18,43,34,16]

输出: 2

解释:

  • 计算每个整数的数位和:[1 + 8 = 9, 4 + 3 = 7, 3 + 4 = 7, 1 + 6 = 7] → [9, 7, 7, 7]
  • 根据数位和排序:[16, 34, 43, 18]。将 1816 交换,再将 4334 交换,得到排序后的数组。
  • 因此,将 nums 排列为排序顺序所需的最小交换次数为 2。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • nums互不相同 的正整数组成。

  • 选择排序的方式,插入排序
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
    public int minSwaps(int[] nums) {
        int[][] tt=new int[nums.length][2];
        for(int i=0;i<nums.length;i++){
            int t=nums[i];
            int r=0;
            while(t>0){
                r+=t%10;
                t/=10;
            }
            tt[i][0]=r;
            tt[i][1]=i;
        }
        Arrays.sort(tt,(a,b)->{
            if(a[0]==b[0]) return nums[a[1]]-nums[b[1]];
            return a[0]-b[0];
        });
        int res=0;
        for(int i=0;i<nums.length;i++){
            int t=tt[i][1];
            while(t!=i){
                int t1=tt[t][1];
                tt[t][1]=t;
                t=t1;
                res++;
            }
        }
        return res;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
impl Solution {
    pub fn min_swaps(nums: Vec<i32>) -> i32 {
        let mut tt: Vec<(i32, usize)> = nums
            .iter()
            .enumerate()
            .map(|(i, &num)| {
                let mut t = num;
                let mut r = 0;

                while t > 0 {
                    r += t % 10;
                    t /= 10;
                }

                (r, i)
            })
            .collect();

        // 排序逻辑
        tt.sort_by(|a, b| {
            if a.0 == b.0 {
                nums[a.1].cmp(&nums[b.1])
            } else {
                a.0.cmp(&b.0)
            }
        });

        let mut res = 0;
        let mut visited = vec![false; nums.len()];

        // 计算交换次数
        for i in 0..nums.len() {
            if visited[i] || tt[i].1 == i {
                continue;
            }

            let mut cycle_size = 0;
            let mut t = i;

            while !visited[t] {
                visited[t] = true;
                t = tt[t].1;
                cycle_size += 1;
            }

            if cycle_size > 1 {
                res += cycle_size - 1;
            }
        }

        res
    }
}
  • 茶神并查集

多个元素相互站位的情况表示存在环(联通块),则排序这些联通块一定可以少排一次,因为联通块中的最后一个元素不需要在排列了,之前其他元素排序时,迫使最后一个元素已经到了正确的位置上。所有最终答案就等于元素总数-联通块的数量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Solution {
//    并查集模板
    class UnionFind {
        int[] tt;
        int[] ss;
//        记录联通块的数量
        int cc;
        public UnionFind(int n) {
            tt=new int[n];
            for(int i=0;i<n;i++){
                tt[i]=i;
            }
            ss=new int[n];
            cc=n;
        }

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

        public void union(int x, int y){
            int a=find(x);
            int b=find(y);
            if(a==b) return;
            if(ss[a]<ss[b]){
                tt[a]=b;
            }else if (ss[a]>ss[b]){
                tt[b]=a;
            }else{
                tt[b]=a;
                ss[a]++;
            }
            cc--;
        }
    }

    public int minSwaps(int[] nums) {
        int n=nums.length;
        int[][] a=new int[n][3];
        for (int i = 0; i < n; i++) {
//            初始化
            int s=0;
            for(int x=nums[i];x>0;x/=10){
                s+=x%10;
            }
//            值
            a[i][0]=s;
//            原始值
            a[i][1]=nums[i];
//            下标
            a[i][2]=i;
        }
//        按照题意排序
        Arrays.sort(a,(x,y)->x[0]!=y[0]?x[0]-y[0]:x[1]-y[1]);
//        新建并查集
        UnionFind u = new UnionFind(n);
        for (int i = 0; i < n; i++) {
//            让下标与联通块来连接
            u.union(i,a[i][2]);
        }
//        如果被联通了的联通块,可以少放置一次
        return n-u.cc;
    }
}

3552. 网格传送门旅游

中等

给你一个大小为 m x n 的二维字符网格 matrix,用字符串数组表示,其中 matrix[i][j] 表示第 i 行和第 j 列处的单元格。每个单元格可以是以下几种字符之一:

  • '.' 表示一个空单元格。
  • '#' 表示一个障碍物。
  • 一个大写字母('A''Z')表示一个传送门。

你从左上角单元格 (0, 0) 出发,目标是到达右下角单元格 (m - 1, n - 1)。你可以从当前位置移动到相邻的单元格(上、下、左、右),移动后的单元格必须在网格边界内且不是障碍物**。**

如果你踏入一个包含传送门字母的单元格,并且你之前没有使用过该传送门字母,你可以立即传送到网格中另一个具有相同字母的单元格。这次传送不计入移动次数,但每个字母对应的传送门在旅程中 最多 只能使用一次。

返回到达右下角单元格所需的 最少 移动次数。如果无法到达目的地,则返回 -1

示例 1:

输入: matrix = [“A..”,".A.","…"]

输出: 2

解释:

img

  • 在第一次移动之前,从 (0, 0) 传送到 (1, 1)
  • 第一次移动,从 (1, 1) 移动到 (1, 2)
  • 第二次移动,从 (1, 2) 移动到 (2, 2)

示例 2:

输入: matrix = [".#…",".#.#.",".#.#.","…#."]

输出: 13

解释:

img

提示:

  • 1 <= m == matrix.length <= 103
  • 1 <= n == matrix[i].length <= 103
  • matrix[i][j]'#''.' 或一个大写英文字母。
  • matrix[0][0] 不是障碍物。
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计