[题目解析]哈希表专题:470、483;数学专题:4、10、14 | 豆包MarsCode AI刷题

100 阅读6分钟

470.珠子颜色去重

问题描述

小S拥有一条由n颗珠子组成的手链,每颗珠子都有一个对应的颜色编号。她希望将手链上相同颜色的珠子进行去重,只保留每种颜色最后出现的那颗珠子,同时保持珠子原来的相对顺序。

测试样例

样例1:

输入:n = 8 ,a = [1, 2, 1, 3, 4, 2, 4, 4] 输出:[1, 3, 2, 4]

样例2:

输入:n = 5 ,a = [5, 5, 5, 5, 5] 输出:[5]

样例3:

输入:n = 6 ,a = [6, 1, 2, 6, 1, 2] 输出:[6, 1, 2]

解决方案

首先遍历该数组,用哈希表记录每一个数的出现次数。然后再次遍历该数组,如果当前数的出现次数等于1,那么把它加入到答案列表中;如果当前数的出现次数大于1,那么让它的出现次数减一。最后得到的答案列表就是题目所要求的,并且保留了原来的相对顺序。

参考代码

import java.util.Arrays;
import java.util.HashMap;

public class Main {
    public static int[] solution(int n, int[] a) {
        // write code here
        HashMap<Integer, Integer> mp = new HashMap<>();
        for (int i = 0; i < n; i++) {
            mp.put(a[i], mp.getOrDefault(a[i], 0) + 1);
        }
        int m = mp.keySet().size();
        int[] res = new int[m];
        int pos = 0;
        for (int i = 0; i < n; i++) {
            if (mp.get(a[i]) == 1) {
                res[pos++] = a[i];
            } else {
                mp.put(a[i], mp.get(a[i]) - 1);
            }
        }
        return res;
    }

    public static void main(String[] args) {
        System.out.println(Arrays.equals(solution(8, new int[]{1, 2, 1, 3, 4, 2, 4, 4}), new int[]{1, 3, 2, 4}));
        System.out.println(Arrays.equals(solution(5, new int[]{5, 5, 5, 5, 5}), new int[]{5}));
        System.out.println(Arrays.equals(solution(6, new int[]{6, 1, 2, 6, 1, 2}), new int[]{6, 1, 2}));
    }
}

483.给定字符串的字符去重问题

问题描述

给定一个字符串 s,你需要通过删除一些字符,使得每个字符在字符串中出现的次数均不相同。你需要找出最少需要删除的字符数量以达到这个目标。

测试样例

样例1:

输入:s = "aab" 输出:0

样例2:

输入:s = "aaabbbcc" 输出:2

样例3:

输入:s = "abcdef" 输出:5

解决方案

首先遍历该字符串,用哈希表记录每个字符的出现次数,然后把每个字符的出现次数存到一个列表里。因为无论删除哪个字符都会让操作次数加一,所以删除任意字符都是可以的。遍历之前得到的列表,如果在这个数字前面出现过和这个数字相同的数字,那么就让它减一,同时操作数加一,直至不相同为止。为了快速知道某个数是否出现过,可以使用HashSet。这样做得到的结果是正确的,因为假设存在一个更小的操作数,那么就会存在两个数是相同的,这就矛盾了,所以得到的结果是最小的。上述做法的时间复杂度是O(n)O(n)

参考代码

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class Main {
    public static int solution(String s) {
        // write code here
        HashMap<Character, Integer> mp = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            mp.put(s.charAt(i), mp.getOrDefault(s.charAt(i), 0) + 1);
        }
        ArrayList<Integer> a = new ArrayList<>();
        HashSet<Integer> S = new HashSet<>();
        for (Character c : mp.keySet()) {
            a.add(mp.get(c));
        }
        S.add(a.get(0));
        int res = 0;
        for (int i = 1; i < a.size(); i++) {
            int t = a.get(i);
            while (S.contains(t)) {
                t--;
                res++;
            }
            if (t > 0) {
                S.add(t);
            }
        }
        return res;
    }

    public static void main(String[] args) {
        System.out.println(solution("aab") == 0);
        System.out.println(solution("aaabbbcc") == 2);
        System.out.println(solution("abcdef") == 5);
    }
}

4.数字分组求偶数和

问题描述

小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。

  • numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。

例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369

测试样例

样例1:

输入:numbers = [123, 456, 789] 输出:14

样例2:

输入:numbers = [123456789] 输出:4

样例3:

输入:numbers = [14329, 7568] 输出:10

解决方案

本题可以使用回溯+剪枝解决。枚举每个小组中选哪个数字,然后判断这些数字的和是否为偶数,如果是偶数,那么答案加一。回溯的时候记得恢复现场。上述做法的时间复杂度为每个小组的数字数量之积。

参考代码

public class Main {
    static int n;
    static int ans;
    static int[] a;

    public static void dfs(int u, int sum) {
        if (u == n) {
            if (sum % 2 == 0) {
                ans++;
            }
            return;
        }
        for (int i = 0; i <= 8; i++) {
            int t = a[u] / (int)Math.pow(10, i) % 10;
            if (t == 0) {
                break;
            }
            sum += t;
            dfs(u + 1, sum);
            sum -= t;
        }
    }

    public static int solution(int[] numbers) {
        // Please write your code here
        n = numbers.length;
        a = numbers;
        ans = 0;
        dfs(0, 0);
        return ans;
    }

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution(new int[]{123, 456, 789}) == 14);
        System.out.println(solution(new int[]{123456789}) == 4);
        System.out.println(solution(new int[]{14329, 7568}) == 10);
    }
}

10.小F的永久代币卡回本计划

问题描述

小F最近迷上了玩一款游戏,她面前有一个永久代币卡的购买机会。该卡片的价格为 a 勾玉,每天登录游戏可以返还 b 勾玉。小F想知道她至少需要登录多少天,才能让购买的永久代币卡回本。

测试样例

样例1:

输入:a = 10, b = 1 输出:10

样例2:

输入:a = 10, b = 2 输出:5

样例3:

输入:a = 10, b = 3 输出:4

解决方案

为了回本,需要登录以来获取的勾玉数量大于等于a,那么就需要登录a/b\lceil a/b \rceil天。上述做法的时间复杂度为O(1)O(1)

参考代码

public class Main {
    public static int solution(int a, int b) {
        // write code here
        return (int)Math.ceil(1.0 * a / b);
    }

    public static void main(String[] args) {
        System.out.println(solution(10, 1) == 10);
        System.out.println(solution(10, 2) == 5);
        System.out.println(solution(10, 3) == 4);
    }
}

14.数组元素之和最小化

问题描述

小C希望构造一个包含n个元素的数组,且满足以下条件:

  1. 数组中的所有元素两两不同。
  2. 数组所有元素的最大公约数为 k
  3. 数组元素之和尽可能小。

任务是输出该数组元素之和的最小值。

测试样例

样例1:

输入:n = 3 ,k = 1 输出:6

样例2:

输入:n = 2 ,k = 2 输出:6

样例3:

输入:n = 4 ,k = 3 输出:30

解决方案

因为数组中所有元素的最大公约数为k,所以数组中所有元素都是k的倍数,又由于数组中所有元素两两不同,所以每个元素都是k的不同倍数,如果想让数组元素之和最小的话,可以让k前面的系数从小到大,也就是从1开始的公差为1的等差数列。所以该数组元素之和的最小值就是(1+2+3+...+n)k(1 + 2 + 3 + ... + n) * k,这个可以用等差数列求和公式进行计算。上述做法的时间复杂度为O(1)O(1)

参考代码

public class Main {
    public static int solution(int n, int k) {
        // write code here
        return n % 2 == 0 ? n / 2 * (n + 1) * k : (n + 1) / 2 * n * k;
    }

    public static void main(String[] args) {
        System.out.println(solution(3, 1) == 6);
        System.out.println(solution(2, 2) == 6);
        System.out.println(solution(4, 3) == 30);
    }
}