【leetcode刷题第36天】1231.分享巧克力、1182.与目标颜色的距离

第三十六天

1231 分享巧克力

你有一大块巧克力,它由一些甜度不完全相同的小块组成。我们用数组 sweetness 来表示每一小块的甜度。

你打算和 K 名朋友一起分享这块巧克力,所以你需要将切割 K 次才能得到K+1 块,每一块都由一些 连续 的小块组成。

为了表现出你的慷慨,你将会吃掉 总甜度最小 的一块,并将其余几块分给你的朋友们。

请找出一个最佳的切割策略,使得你所分得的巧克力 总甜度最大,并返回这个最大总甜度

方法

由于所有的巧克力必须连续分,我们可以使用二分搜索来确定答案,然后再通过具体相应判断算法来判断某一个答案是否合法。本题可以使用二分搜索答案的关键点在于,如果res是答案,那么比res大的一定不行,而比res小的一定也可以,它具有二段性。

因此,我们使用二分来找这个res,然后判断res是否可达,如果发现res可达,我们就尽可能的让res大,否则让res变小。直到我们找到答案为止。

对于一个答案是否可达,我们可以通过模拟切巧克力的过程,让切出来的大小在超过res并尽可能的靠近res,然后我们统计一下所切的巧克力的块数,如果超过了k+1块(分给k个朋友,自己也需要一块,所以需要k+1块)说明这个res是可以实现的,即可以分出k+1块,让每一块的大小不小于res

然后我们需要确定搜索的范围,容易知道搜索的左边界是整个巧克力数组的最小值,对于搜索的右边界,我们知道最极端的情况是k+1所分到的巧克力相同,因此右边界是所有巧克力总和除以k+1

class Solution {
    public int maximizeSweetness(int[] sweetness, int k) {
        int l = 1000000;
        int[] sumI = new int[sweetness.length + 1];
        for (int i = 0; i < sweetness.length; ++i){
            sumI[i + 1] = sweetness[i] + sumI[i];
            l = Math.min(l, sweetness[i]);//搜索的左边界
        }
        int r = sumI[sumI.length - 1] / (k + 1);//搜索的右边界
        
        //二分搜索答案
        while (l <= r){
            int mid = (l + r) >> 1;
            if (isOk(sumI, mid, k + 1)) l = mid + 1;//如果能够满足 我们尝试调大
            else  r = mid - 1;//不能满足 调小一点
        }
        return r;//返回能够满足的最大值
    }

    public boolean isOk(int[] sum, int target, int nums){
        int count = 0;
        int s = 0, e = 1;
        //模拟切巧克力
        while (e < sum.length){
            if (sum[e] - sum[s] < target) e++;
            else{
                count++; //超过了target 切下一块 统计块数
                s = e;
                e++;
            }
        }
        return count >= nums; //能不能切出k+1块
    }
}

1182 与目标颜色的距离

给你一个数组 colors,里面有 123 三种颜色。

我们需要在 colors 上进行一些查询操作 queries,其中每个待查项都由两个整数 ic 组成。

现在请你帮忙设计一个算法,查找从索引 i 到具有目标颜色 c 的元素之间的最短距离。

如果不存在解决方案,请返回 -1

方法

和上一题的思路大致相同,我们可以二分搜索这个最短距离,因为这个最短距离是具有二段性的,如果最短距离是distance,那么小于distance的一定不行,而大于等于distance的一定可以。我们使用二分去搜索这个最短距离,注意距离是双向的,因此左右都要找。

class Solution {
    public List<Integer> shortestDistanceColor(int[] colors, int[][] queries) {
        ArrayList<Integer> res = new ArrayList<>();
        Map<Point, Integer> map = new HashMap<>();
        for (int[] query : queries){
            if (map.containsKey(new Point(query))){
                res.add(map.get(new Point(query)));
                continue;
            } 
            int l = 0, r = Math.max(colors.length - query[0] - 1, query[0]);//确定搜索范围 左边界是0 右边界是到数组开头 和 尾部两者距离中的最大值
            boolean flag = false;
            while (l <= r){
                int mid = (l + r) >> 1;
                if (isOk(colors, mid, query[0], query[1])) {r = mid - 1;flag = true;}
                else l = mid + 1;
            }
            int ans = flag ? l : -1;
            res.add(ans);
            map.put(new Point(query), ans);
        }
        return res;
    }
	//判断在所给的distance内能不能找到答案
    public boolean isOk(int[] colors, int distance, int start, int target) {
        for (int i = 0; i <= distance; ++i){
            int count = 0;
            if (start + i < colors.length){
                if (colors[start + i] == target) return true;
                count++;
            }
            if (start - i >= 0){
                if (colors[start - i] == target) return true;
                count++;
            }
            if (count == 0) break;
        }
        return false;
    }
}

class Point{
    int x;int y;
    Point(int[] a){x = a[0]; y = a[1];}
    @Override public boolean equals(Object p){
        Point cmp = (Point) p;
        return cmp.x == x && cmp.y == y;
    }
    @Override public int hashCode(){return x | y;}
}


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值