LeetCode 2679. 矩阵中的和

2679. 矩阵中的和

给你一个下标从 0 开始的二维整数数组 nums 。一开始你的分数为 0 。你需要执行以下操作直到矩阵变为空:

矩阵中每一行选取最大的一个数,并删除它。如果一行中有多个最大的数,选择任意一个并删除。
在步骤 1 删除的所有数字中找到最大的一个数字,将它添加到你的 分数 中。
请你返回最后的 分数 。

示例 1:
输入:nums = [[7,2,1],[6,4,2],[6,5,3],[3,2,1]]
输出:15
解释:第一步操作中,我们删除 7 ,6 ,6 和 3 ,将分数增加 7 。下一步操作中,删除 2 ,4 ,5 和 2 ,将分数增加 5 。最后删除 1 ,2 ,3 和 1 ,将分数增加 3 。所以总得分为 7 + 5 + 3 = 15 。

class Solution {
    // 2、建堆 优先级队列
    public int matrixSum(int[][] nums) {
        int n = nums.length;
        int m = nums[0].length;
        PriorityQueue<Integer>[] priorityQueue  = new PriorityQueue[n];
        for (int i = 0; i < n; i++) {
            priorityQueue[i] = new PriorityQueue<Integer>((a, b) -> b - a);
            for (int j = 0; j < m; j++) {
                priorityQueue[i].offer(nums[i][j]);
            }
        }
        int score = 0;
        for (int j = 0; j < m; j++) {
            int max = 0;
            for (int i = 0; i < n; i++) { // 删除每一行的最大值即堆顶元素
                max = Math.max(max, priorityQueue[i].poll());
            }
            score += max;
        }
        return score;
    }

    // 1、每一行排序,添加比较的每一列最大值
    public int matrixSum1(int[][] nums) {
        int n = nums.length;
        int m = nums[0].length;
        for (int i = 0; i < n; i++) {
            Arrays.sort(nums[i]);
        }
        int score = 0;
        for (int j = 0; j < m; j++) { // 列
            int max = 0;
            for (int i = 0; i < n; i++) {
                max = Math.max(max, nums[i][j]);
            }
            score += max;
        }
        return score;
    }
}

2600. K 件物品的最大和

袋子中装有一些物品,每个物品上都标记着数字 1 、0 或 -1 。

给你四个非负整数 numOnes 、numZeros 、numNegOnes 和 k 。

袋子最初包含:

numOnes 件标记为 1 的物品。
numZeroes 件标记为 0 的物品。
numNegOnes 件标记为 -1 的物品。
现计划从这些物品中恰好选出 k 件物品。返回所有可行方案中,物品上所标记数字之和的最大值。

示例 1:
输入:numOnes = 3, numZeros = 2, numNegOnes = 0, k = 2
输出:2
解释:袋子中的物品分别标记为 {1, 1, 1, 0, 0} 。取 2 件标记为 1 的物品,得到的数字之和为 2 。
可以证明 2 是所有可行方案中的最大值。

public int kItemsWithMaximumSum(int numOnes, int numZeros, int numNegOnes, int k) {
        // 1 可全取
        // 取全部 1 和 部分 0
        // 取全部 1, 0 和部分 -1
        if (k <= numOnes) {
            return k;
        } else if (k <= numOnes + numZeros) { // numOnes < k && k < numOnes + numZeros
            return numOnes;
        } else {
            return numOnes - (k - numOnes - numZeros);
        }
    }

445. 两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

在这里插入图片描述

示例1:
输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<Integer> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        while (l1 != null) {
            stack1.add(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.add(l2.val);
            l2 = l2.next;
        }
        int carry = 0; // 记得进位
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int val1 = stack1.isEmpty() ? 0: stack1.pop();
            int val2 = stack2.isEmpty() ? 0 : stack2.pop();
            int sum = val1 + val2 + carry;
            int nextVal = sum % 10;
            carry = sum / 10;
            ListNode nextCur = new ListNode(nextVal); // 下一个节点
            nextCur.next = ans;
            ans = nextCur; // 新的 head
        }
        return ans;
    }
}

3. 无重复字符的最长子串

添加链接描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

class Solution {
    // 滑动窗口
    //  key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0;
        Map<Character, Integer> map = new HashMap<>();
        for (int end = 0, start = 0; end < n; end++) {
            if (map.containsKey(s.charAt(end))) {
                start = Math.max(start, map.get(s.charAt(end)));
            }
            ans = Math.max(ans, end - start + 1);
            map.put(s.charAt(end), end + 1); // 下次 start 更新的位置
        }
        return ans;
    }
}

1017. 负二进制转换

添加链接描述
给你一个整数 n ,以二进制字符串的形式返回该整数的 负二进制(base -2)表示。

注意,除非字符串就是 “0”,否则返回的字符串中不能含有前导零。

示例 1:
输入:n = 2
输出:“110”
解释:(-2)2 + (-2)1 = 2

class Solution {
    // 基数为 -2,负二进制的余数可能有0,1,-1,要保证余数为正
    public String baseNeg2(int n) {
        if (n == 0) {
            return "0";
        }
        StringBuilder ans = new StringBuilder();
        while (n != 0) {
            int remain = Math.abs(n % (-2));
            ans.append(remain == 0 ? "0" : "1");
            n = (n - remain) / (-2);
        }
        return ans.reverse().toString();
    }
}

2404. 出现最频繁的偶数元素

添加链接描述
给你一个整数数组 nums ,返回出现最频繁的偶数元素。

如果存在多个满足条件的元素,只需要返回 最小 的一个。如果不存在这样的元素,返回 -1 。

示例 1:
输入:nums = [0,1,2,2,4,4,1]
输出:2
解释:
数组中的偶数元素为 0、2 和 4 ,在这些元素中,2 和 4 出现次数最多。
返回最小的那个,即返回 2 。

class Solution {
    public static int mostFrequentEven(int[] nums) {
        int max = 0; // 最频繁次数
        int ans = -1;
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            if (num % 2 == 0) {
                map.put(num, map.getOrDefault(num, 0) + 1);
                if (max < map.get(num)) {
                    max = map.get(num); // 更新出现最频繁 次数 
                    ans = num; // 更新出现最频繁 元素 
                } else if (max == map.get(num)) { // 次数相同时 结果为最小的元素
                    ans = Math.min(ans, num);
                }
            }
        }
        return ans;
    }
}

831. 隐藏个人信息

添加链接描述
给你一条个人信息字符串 s ,可能表示一个 邮箱地址 ,也可能表示一串 电话号码 。返回按如下规则 隐藏 个人信息后的结果:

电子邮件地址:

一个电子邮件地址由以下部分组成:

一个 名字 ,由大小写英文字母组成,后面跟着
一个 ‘@’ 字符,后面跟着
一个 域名 ,由大小写英文字母和一个位于中间的 ‘.’ 字符组成。‘.’ 不会是域名的第一个或者最后一个字符。
要想隐藏电子邮件地址中的个人信息:

名字 和 域名 部分的大写英文字母应当转换成小写英文字母。
名字 中间的字母(即,除第一个和最后一个字母外)必须用 5 个 "*****" 替换。
电话号码:

一个电话号码应当按下述格式组成:

电话号码可以由 10-13 位数字组成
后 10 位构成 本地号码
前面剩下的 0-3 位,构成 国家代码
利用 {'+', '-', '(', ')', ' '} 这些 分隔字符 按某种形式对上述数字进行分隔
要想隐藏电话号码中的个人信息:

移除所有 分隔字符
隐藏个人信息后的电话号码应该遵从这种格式:
"***-***-XXXX" 如果国家代码为 0 位数字
"+*-***-***-XXXX" 如果国家代码为 1 位数字
"+**-***-***-XXXX" 如果国家代码为 2 位数字
"+***-***-***-XXXX" 如果国家代码为 3 位数字
“XXXX” 是最后 4 位 本地号码

示例 1:
输入:s = "LeetCode@LeetCode.com"
输出:"l*****e@leetcode.com"
解释:s 是一个电子邮件地址。
名字和域名都转换为小写,名字的中间用 5 个 * 替换。

class Solution {
    // 2、
    static String[] country = {"", "+*-", "+**-", "+***-"};

    public String maskPII(String s) {
        int atIndex = s.indexOf("@");
        StringBuilder stringBuilder = new StringBuilder();
        if (atIndex > 0) { // 电子邮件地址
            stringBuilder.append(s.charAt(0) + "*****" + s.substring(atIndex - 1));
            return stringBuilder.toString().toLowerCase();
        } else { // 电话号码
            s = s.replaceAll("[^0-9]", "");
            stringBuilder.append(country[s.length() - 10] + "***-***-" + s.substring(s.length() - 4));
            return stringBuilder.toString();
        }
    }

    // 1、
    public static String maskPII1(String s) {
        int n = s.length();
        // 1、分析是邮件地址还是电话号码
        boolean flg = false;
        for (int i = n - 1; i >= 0; i--) {
            if (s.charAt(i) == '.') {
                flg = true;
                break;
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        // 2、电子邮件地址
        if (flg) {
            int index = s.indexOf("@"); // 获取 @ 下标,拼接首尾字母,@ 到结尾
            stringBuilder.append(s.charAt(0) + "*****" + s.charAt(index - 1) + s.substring(index));
            return stringBuilder.toString().toLowerCase();
        }
        // 3、电话号码
        int cnt = 0;
        for (int i = 0; i < n; i++) { // 统计电话号码位数
            if (Character.isDigit(s.charAt(i))) {
                cnt++;
            }
        }
        if (cnt == 10) { // 国家代码 0 位
            stringBuilder.append("***-***-");
        } else if (cnt == 11) { // 国家代码 1 位
            stringBuilder.append("+*-***-***-");
        } else if (cnt == 12) { // 国家代码 2 位
            stringBuilder.append("+**-***-***-");
        } else if (cnt == 13) { // 国家代码 3 位
            stringBuilder.append("+***-***-***-");
        }
        StringBuilder sb = new StringBuilder(); // 后四位号码 可能有符号 '-'
        int digitCnt = 0;
        for (int i = n - 1; i >= 0; i--) {
            if (Character.isDigit(s.charAt(i))) {
                sb.append(s.charAt(i));
                digitCnt++;
                if (digitCnt == 4) {
                    break;
                }
            }
        }
        stringBuilder.append(sb.reverse());
        return stringBuilder.toString();
    }
}

2367. 算术三元组的数目

添加链接描述
给你一个下标从 0 开始、严格递增 的整数数组 nums 和一个正整数 diff 。如果满足下述全部条件,则三元组 (i, j, k) 就是一个 算术三元组 :

i < j < k ,
nums[j] - nums[i] == diff 且
nums[k] - nums[j] == diff
返回不同 算术三元组 的数目。

示例 1:
输入:nums = [0,1,4,6,7,10], diff = 3
输出:2
解释:
(1, 2, 4) 是算术三元组:7 - 4 == 3 且 4 - 1 == 3 。
(2, 4, 5) 是算术三元组:10 - 7 == 3 且 7 - 4 == 3 。

class Solution {
    // 2、三指针 O(N)  下标只增不减
    public int arithmeticTriplets(int[] nums, int diff) {
        int cnt = 0;
        int n = nums.length;
        for (int i = 0, j = 1, k = 2; i < n - 2 && j < n - 1 && k < n; i++) {
            j = Math.max(j, i + 1);
            while (j < n - 1 && nums[j] - nums[i] < diff) { // 对于当前 x,找 x + diff
                j++;
            }
            if (j >= n - 1 || nums[j] - nums[i] > diff) { // 当前 x,没有满足的三元组
                continue;
            }
            k = Math.max(k, j + 1);
            while (k < n && nums[k] - nums[j] < diff) {
                k++;
            }
            if (k < n && nums[k] - nums[j] == diff) { // 满足的三元组加一
                cnt++;
            }
        }
        return cnt;
    }

    // 2、哈希 O(N)  数组严格递增,没有重复
    // 等差数列 ->  x,  x+diff,  x+2*diff
    public int arithmeticTriplets2(int[] nums, int diff) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        int cnt = 0;
        for (int x : nums) {
            if (set.contains(x + diff) && set.contains(x + 2 * diff)) {
                cnt++;
            }
        }
        return cnt;
    }

    // 1、暴力枚举
    public int arithmeticTriplets1(int[] nums, int diff) {
        int cnt = 0;
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (nums[j] - nums[i] != diff) {
                    continue;
                }
                for (int k = j + 1; k < n; k++) {
                    if (nums[k] - nums[j] == diff) {
                        cnt++;
                    }
                }
            }
        }
        return cnt;
    }
}

1637. 两点之间不包含任何点的最宽垂直区域

添加链接描述
给你 n 个二维平面上的点 points ,其中 points[i] = [xi, yi] ,请你返回两点之间内部不包含任何点的 最宽垂直区域 的宽度。

垂直区域 的定义是固定宽度,而 y 轴上无限延伸的一块区域(也就是高度为无穷大)。 最宽垂直区域 为宽度最大的一个垂直区域。

请注意,垂直区域 边上 的点 不在 区域内。

示例 1:​
输入:points = [[8,7],[9,9],[7,4],[9,7]]
输出:1
解释:红色区域和蓝色区域都是最优区域。

class Solution {
    // 按横坐标排序,依次求出所有相邻点的横坐标距离,返回最大值 (与 y 轴无关)
    public int maxWidthOfVerticalArea(int[][] points) {
        Arrays.sort(points, (a, b) -> a[0] - b[0]);
        int max = 0;
        for (int i = 1; i < points.length; i++) {
            max = Math.max(max, points[i][0] - points[i - 1][0]);
        }
        return max;
    }
}

1641. 统计字典序元音字符串的数目

添加链接描述
给你一个整数 n,请返回长度为 n 、仅由元音 (a, e, i, o, u) 组成且按 字典序排列 的字符串数量。

字符串 s 按 字典序排列 需要满足:对于所有有效的 i,s[i] 在字母表中的位置总是与 s[i+1] 相同或在 s[i+1] 之前。

示例 1:
输入:n = 1
输出:5
解释:仅由元音组成的 5 个字典序字符串为 [“a”,“e”,“i”,“o”,“u”]
示例 2:

输入:n = 2
输出:15
解释:仅由元音组成的 15 个字典序字符串为
[“aa”,“ae”,“ai”,“ao”,“au”,“ee”,“ei”,“eo”,“eu”,“ii”,“io”,“iu”,“oo”,“ou”,“uu”]
注意,“ea” 不是符合题意的字符串,因为 ‘e’ 在字母表中的位置比 ‘a’ 靠后

class Solution {
    // 2、C(n+4,4)
    public int countVowelStrings(int n) {
        return (n + 4) * (n + 3) * (n + 2) * (n + 1) / 24;
    }

    // 1、动态规划
    public int countVowelStrings3(int n) {
        int[] dp = new int[5];
        Arrays.fill(dp, 1);
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < 5; j++) {
                dp[j] += dp[j - 1];
            }
        }
        // n = 5 ——> [1, 5, 15, 35, 70]
        return Arrays.stream(dp).sum();
    }

    // dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    // [1, 1, 1, 1, 1]
    // [1, 2, 3, 4, 5]
    // [1, 3, 6, 10, 15]
    // [1, 4, 10, 20, 35]
    // [1, 5, 15, 35, 60]
    public int countVowelStrings2(int n) {
        int[][] dp = new int[n][5];
        for (int i = 0; i < 5; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < n; i++) {
            // dp[i][0] = dp[i - 1][0];
            dp[i][0] = 1;
            for (int j = 1; j < 5; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return Arrays.stream(dp[n - 1]).sum();
    }
    
    public int countVowelStrings1(int n) {
        int a = 1, e = 1, i = 1, o = 1, u = 1;
        for (int k = 1; k < n; k++) {
            a = a + e + i + o + u;
            e = e + i + o + u;
            i = i + o + u;
            o = o + u;
            u = u;
        }
        return a + e + i + o + u;
    }
}

2395. 和相等的子数组

添加链接描述
给你一个下标从 0 开始的整数数组 nums ,判断是否存在 两个 长度为 2 的子数组且它们的 和 相等。注意,这两个子数组起始位置的下标必须 不相同 。

如果这样的子数组存在,请返回 true,否则返回 false 。

子数组 是一个数组中一段连续非空的元素组成的序列。

示例 1:
输入:nums = [4,2,4]
输出:true
解释:元素为 [4,2] 和 [2,4] 的子数组有相同的和 6 。

class Solution {
    public boolean findSubarrays(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int i = 1; i < nums.length; i++) {
            int sum = nums[i - 1] + nums[i];
            if (set.contains(sum)) {
                return true;
            }
            set.add(sum);
        }
        return false;
    }
}

1574. 删除最短的子数组使剩余数组有序

给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。

一个子数组指的是原数组中连续的一个子序列。

请你返回满足题目要求的最短子数组的长度。

示例 1:
输入:arr = [1,2,3,10,4,2,3,5]
输出:3
解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5] 。
另一个正确的解为删除子数组 [3,10,4] 。

class Solution {
    // 双指针  枚举左端点,移动右端点
    public int findLengthOfShortestSubarray(int[] arr) {
        int n = arr.length;
        int r = n - 1;
        // 从右端点开始,arr[r] 最大,r 到达非递减的位置
        while (r > 0 && arr[r - 1] <= arr[r]) {
            r--;
        }
        // arr 为非递减数组,不需要删除
        if (r == 0) {
            return 0;
        }
        // 需要删除的是 [0-r) 之间,最多 [0-r) 都需要删除
        int ans = r;
        for (int l = 0; l == 0 || arr[l - 1] <= arr[l]; l++) { // 当前 l 与左边非递减,判断是否与 arr[r] 非递减
            while (r < n && arr[l] > arr[r]) {
                r++;
            }
            // 需要删除的是 [l-r) 之间
            ans = Math.min(ans, r - l - 1);
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三春去后诸芳尽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值