力扣-第 235 场周赛

本文旨在对于笔者日常比赛的整理复盘,如果有不足的地方,欢迎大家在评论区指出


Question one: 截断句子
题目描述

句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

例如,"Hello World""HELLO""hello world hello world" 都是句子。
给你一个句子 s​​​​​​ 和一个整数 k​​​​​​ ,请你将 s​​ 截断 ​,​​​使截断后的句子仅含 前 k​​​​​​ 个单词。返回 截断 s​​​​​​ 后得到的句子。

题目链接
题目分析

句子的最大长度为500,所以这道题的解法就比较任意,题目中限制了句子中的每一个单词之间都是单个空格隔开,所以我们可以直接调用java中的split方法来做,之后返回分割数组的前k个就好了

解题代码

Java

class Solution {
    public String truncateSentence(String s, int k) {
        String[] arr = s.split(" ");
        StringBuilder res = new StringBuilder();
        for(int i=0; i<k; i++){
            if(i != k-1) res.append(arr[i] + " ");
            else res.append(arr[i]);
        }
        return res.toString();
    }
}

Question two: 查找用户活跃分钟数
题目描述

给你用户在 LeetCode 的操作日志,和一个整数 k 。日志用一个二维整数数组 logs 表示,其中每个 logs[i] = [IDi, timei] 表示 ID 为 IDi 的用户在 timei 分钟时执行了某个操作。

多个用户 可以同时执行操作,单个用户可以在同一分钟内执行 多个操作 。

指定用户的 用户活跃分钟数(user active minutes,UAM) 定义为用户对 LeetCode 执行操作的 唯一分钟数 。 即使一分钟内执行多个操作,也只能按一分钟计数。

请你统计用户活跃分钟数的分布情况,统计结果是一个长度为 k 且 下标从 1 开始计数 的数组 answer ,对于每个 j(1 <= j <= k),answer[j] 表示 用户活跃分钟数 等于 j 的用户数。

返回上面描述的答案数组 answer 。

题目链接
题目分析

首先这道题的思路就是统计每一个 I D ID ID活跃的所有分钟数,并对每一个 I D ID ID对应的分钟集合进行去重,最后遍历所有的 I D ID ID,将该 I D ID ID对应的活跃次数累加到答案中,而 I D ID ID的范围有 1 0 9 10^9 109,所以我们想到使用map来做,对于分钟数的去重想到了set,这道题也就迎刃而解了

解题代码

Java

class Solution {
    public int[] findingUsersActiveMinutes(int[][] logs, int k) {
        Map<Integer, Set<Integer>> map = new HashMap<>();
        for(int[] log:logs){
            Set<Integer> set = map.get(log[0]);
            if(set == null){
                set = new HashSet<Integer>();
                map.put(log[0], set);
            }
            map.get(log[0]).add(log[1]);
        }
        
        int[] res = new int[k];
        for(Integer id:map.keySet()){
            res[map.get(id).size()-1] += 1;
        }
        return res;
    }
}

Question three: 绝对差值和
题目描述

给你两个正整数数组 nums1 和 nums2 ,数组的长度都是 n 。

数组 nums1 和 nums2 的 绝对差值和 定义为所有 |nums1[i] - nums2[i]|(0 <= i < n)的 总和(下标从 0 开始)。

你可以选用 nums1 中的 任意一个 元素来替换 nums1 中的 至多 一个元素,以 最小化 绝对差值和。

在替换数组 nums1 中最多一个元素 之后 ,返回最小绝对差值和。因为答案可能很大,所以需要对 109 + 7 取余 后返回。

|x| 定义为:

  • 如果 x >= 0 ,值为 x ,或者
  • 如果 x <= 0 ,值为 -x
题目链接
题目分析

首先翻译一下题目大意,就是我们要最小化num1nums2的绝对值差的和,我们只可以将nums1中的一个元素换成nums1中已经存在的元素,题目要求我们求出这个最小的绝对值差和,其中绝对值差和的定义为 ∑ i = 1 n ( ∣ n u m s 1 [ i ] − n u m s 2 [ i ] ∣ ) \sum_{i=1}^{n}(|nums1[i]-nums2[i]|) i=1n(nums1[i]nums2[i]),我们可以这样想,因为只可以换一个元素,所以我们必然要找到nums1nums2中绝对值差值最大的一组值,之后将nums1中的值替换为nums1中与nums2最接近的值,举一个题目中的例子:

nums1 = [1, 7, 5]
nums2 = [2, 3, 5]

1. 首先找到max(|nums1[i]-nums2[i]|) = nums1[1]-nums2[1] = |7-3| = 4(i=1)
2. 之后再nums1中找到与nums2[1]最接近的那个数字也就是1或者5,这里用1来举例,我们
   将nums1中的7替换为1:nums1 = [1, 1, 5],nums2 = [2, 3, 5],此时的绝对值
   差和达到最小为3
解题代码

Java

class Solution {
    public int minAbsoluteSumDiff(int[] nums1, int[] nums2) {
        int MOD = 1000000007;
        
        int n = nums1.length;
        
        // 求出二者的绝对值差的和
        long absSum = 0;
        for(int i=0; i<n; i++){
            absSum += Math.abs(nums1[i]-nums2[i]);
        }
        
        // 找到绝对值差最大的那组下标
        int maxIdx = 0;
        for(int i=0; i<n; i++){
            if(Math.abs(nums1[i]-nums2[i])>Math.abs(nums1[maxIdx]-nums2[maxIdx])){
                maxIdx = i;
            }
        }
        
        // 找到nums1中最接近nums2[maxIdx]的值
        int tarIdx = 0;
        for(int i=0; i<n; i++){
            if(Math.abs(nums1[i]-nums2[maxIdx])<Math.abs(nums1[tarIdx]-nums2[maxIdx])){
                tarIdx = i;
            }
        }
        long dif = Math.abs(nums1[tarIdx]-nums2[maxIdx])-Math.abs(nums1[maxIdx]-nums2[maxIdx]);
        return (int)((absSum+dif)%MOD);
    }
}

Question four: 序列中不同最大公约数的数目
题目描述

给你一个由正整数组成的数组 nums 。

数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。

  • 例如,序列 [4,6,16] 的最大公约数是 2 。

数组的一个 子序列 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。

  • 例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。

计算并返回 nums 的所有 非空 子序列中 不同 最大公约数的 数目 。

题目链接
题目分析

这道题最难分析的是如何遍历出所有的情况,我们可以直接枚举最大公约数的所有情况,也就是从1枚举到数组中的最大值,这样也就枚举了答案的所有情况,之后我们使用g[y]表示y的倍数的最大公约数,那么如果g[y] = y也就是说数组中存在某个序列的最大公约数为y,此时答案加1,也就是最大公约数的种类多了一个,而对于g[y]的求解就是枚举数组中所有数字x的约数y,不断的将g[y]与x求最大公约数,最后进行上面的判断就好了

解题代码

Java

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

    public int countDifferentSubsequenceGCDs(int[] nums) {
        int n = nums.length;
        
        // 找到数组中元素的最大值
        int maxV = 0;
        for(int i=0; i<n; i++) maxV = Math.max(maxV, nums[i]);
        
        int[] g = new int[maxV+1]; // g[i]表示i的倍数的最大公约数
        for(int x:nums){
            for(int y=1; y<=x/y; y++){
                if(x%y==0){
                    g[y]=gcd(g[y], x);
                    g[x/y]=gcd(g[x/y], x);
                }
            }
        }
        
        int res = 0;
        for(int i=1; i<=maxV; i++){
            if(g[i]==i) res += 1;
        }
        return res;
    }
}

你可能感兴趣的:(比赛合集,算法)