Leetcode 第391场周赛 问题和解法

哈沙德数

如果一个整数能够被其各个数位上的数字之和整除,则称之为哈沙德数(Harshadnumber)。给你一个整数x。如果x是哈沙德数,则返回x各个数位上的数字之和,否则,返回-1。
示例1:

输入:x=18

输出:9

解释:

x各个数位上的数字之和为9。18能被9整除。因此18是哈沙德数,答案是9。

解题思路

本题是一道简单题,只要通过取模运算获取每一位的数字,并求和之后计算即可。

class Solution {
    public int sumOfTheDigitsOfHarshadNumber(int x) {
        int sum=0;
        int tem=x;
        while(tem>0){
            sum+=tem%10;
            tem/=10;
        }
        return x%sum==0?sum:-1;
    }
}

换水问题 II

给你两个整数numBottles和numExchange。

numBottles代表你最初拥有的满水瓶数量。在一次操作中,你可以执行以下操作之一:

  • 喝掉任意数量的满水瓶,使它们变成空水瓶。

  • 用numExchange个空水瓶交换一个满水瓶。然后,将numExchange的值增加1。

注意,你不能使用相同的numExchange值交换多批空水瓶。例如,如果numBottles3并且numExchange1,则不能用3个空水瓶交换成3个满水瓶。

返回你最多可以喝到多少瓶水。
示例 1:
在这里插入图片描述

输入:numBottles = 13, numExchange = 6
输出:15
解释:上表显示了满水瓶的数量、空水瓶的数量、numExchange 的值,以及累计喝掉的水瓶数量。

解题思路

  1. 一开始将所有的都喝完
  2. 然后循环判断空瓶能否兑换新的水瓶
class Solution {
    public int maxBottlesDrunk(int numBottles, int numExchange) {
        int res=0;
        res+=numBottles;
        while(numBottles>=numExchange){
            numBottles-=numExchange;
            numExchange++;
            numBottles++;
            res++;
        }
        return res;
    }
}

交替子数组计数

给你一个二进制数组nums。

如果一个子数组中不存在两个相邻元素的值相同的情况,我们称这样的子数组为交替子数组。

返回数组nums中交替子数组的数量。

示例 1:

输入: nums = [0,1,1,1]

输出: 5

解释:

以下子数组是交替子数组:[0][1][1][1] 以及 [0,1]

解题思路

最长的一个符合条件的子数组中,它的所有子数组肯定是全部都符合条件的,所有我们只需要将数组分成很多个符合条件的子数组然后单独计数就行

class Solution {
    public long countAlternatingSubarrays(int[] nums) {
        long ans = 0, cnt = 0;
        for (int i = 0; i < nums.length; i++) {
            cnt = i > 0 && nums[i] == nums[i - 1] ? 1 : cnt + 1;
            ans += cnt; 
        }
        return ans;
    }
}

最小化曼哈顿距离

给你一个下标从0开始的数组points,它表示二维平面上一些点的整数坐标,其中points[i]=[xi,yi]。

两点之间的距离定义为它们的曼哈顿距离。

请你恰好移除一个点,返回移除后任意两点之间的最大距离可能的最小值。

示例 1:

输入:points = [[3,10],[5,15],[10,2],[4,4]]
输出:12
解释:移除每个点后的最大距离如下所示:
- 移除第 0 个点后,最大距离在点 (5, 15)(10, 2) 之间,为 |5 - 10| + |15 - 2| = 18- 移除第 1 个点后,最大距离在点 (3, 10)(10, 2) 之间,为 |3 - 10| + |10 - 2| = 15- 移除第 2 个点后,最大距离在点 (5, 15)(4, 4) 之间,为 |5 - 4| + |15 - 4| = 12- 移除第 3 个点后,最大距离在点 (5, 15)(10, 2) 之间的,为 |5 - 10| + |15 - 2| = 18 。
在恰好移除一个点后,任意两点之间的最大距离可能的最小值是 12

解题思路

  • 1.假设原始数组的最大曼哈顿距离为点u和点v间的距离。容易证明,要删除的那个点一定是点
    u或者点v (否则的话u和v之间那条边仍然存在,最大曼哈顿距离不会改变)
  • 2.现在找数组的最大曼哈顿距离,暴力求解是平方复杂度,会超时。那么如何减少复杂度呢?
    考虑下标i<j,距离可以表示为|xj -xi| +|yj -yi|,不妨将点集按x排序,这样两点的距离就可以简化为xj -エi +|Иj-Yi|,去掉绝对值可得两点间的距离为:max[(xj +yj)-(xi+yi),(xj-yj)-(xi-yi)]因此可以在遍历j的同时使用两个最小堆,一个维护xi+yi的最小值,一个维护xi-yi的最小值,这样复杂度就会减少到0(nlogn)
  • 3.注意我们还需要找到使得曼哈顿距离最大的两个点u和点v,因此在求原数组最大距离时需要顺便保存u和v的下标;然后分别屏蔽点u和点v,求屏蔽后数组的最大距离,两者间的较小者即为所求
public class Solution {
    public int minimumDistance(int[][] points) {
        Arrays.sort(points, (o1, o2) -> o1[0] - o2[0]);
        PriorityQueue<int[]> pq1 = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        PriorityQueue<int[]> pq2 = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        int maxDist = Integer.MIN_VALUE;
        int[] maxIds = new int[2];
        for(int i = 0;i < points.length;++i){
            int x = points[i][0], y = points[i][1];
            if(!pq1.isEmpty()) {
                int dist1 = (x+y) - pq1.peek()[0];
                int dist2 = (x-y) - pq2.peek()[0];
                if(dist1 > maxDist || dist2 > maxDist){
                    maxDist = Math.max(dist1, dist2);
                    maxIds[0] = dist1 > dist2 ? pq1.peek()[1] : pq2.peek()[1];
                    maxIds[1] = i;
                }
            }
            pq1.offer(new int[]{x+y, i});
            pq2.offer(new int[]{x-y, i});
        }
        int maxDist1 = maskedDistance(points, maxIds[0]);
        int maxDist2 = maskedDistance(points, maxIds[1]);
        return Math.min(maxDist1, maxDist2);
    }
    
    // 删除点point[mask]后,求数组任意两点间的最大距离
    public int maskedDistance(int[][] points, int mask){
        PriorityQueue<int[]> pq1 = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        PriorityQueue<int[]> pq2 = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        int maxDist = Integer.MIN_VALUE;
        for(int i = 0;i < points.length;++i){
            if(i == mask) continue;
            int x = points[i][0], y = points[i][1];
            if(!pq1.isEmpty()) {
                int dist1 = (x+y) - pq1.peek()[0];
                int dist2 = (x-y) - pq2.peek()[0];
                if(dist1 > maxDist || dist2 > maxDist) maxDist = Math.max(dist1, dist2);
            }
            pq1.offer(new int[]{x+y, i});
            pq2.offer(new int[]{x-y, i});
        }
        return maxDist;
    }
}

来源

LeetCode周赛

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吴代庄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值