LeetCode周赛360

LeetCode周赛360

A题

B题

题意

要求构造一个数组arr,长度为n,里面任意两个元素相加之和不等于target。求这样一个数组的和的最小值。

和双周赛359的B题类似,先从1构造到target >> 1,然后再从target开始继续构造。

代码
class Solution {
    public long minimumPossibleSum(int n, int target) {
        int p = target / 2 + 1;
        long sum = 0;
        int start = 1;
        while(--n >= 0) {
            sum += start++;
            if (start == p) {
                start = target;
            }
        }
        return sum;
    }
}

C题

题意

给出一个数组arr,里面的每个元素的值保证为2的幂数,每个元素a又可以被拆分成两个x,x + x = a。要求求出最少执行多少次拆分之后数组里面的某一个子序列的和为target。

思路

我们可以先将target视为一个二进制数,那么题目要求的就是target中每一个1都需要在原数组中出现,那么我们对每一个1,从小到大开始求是否会在原数组中出现。我们知道一个理论,如果原数组中,小于等于当前位上的2进制数之和大于等于当前1所代表的数的值,那么一定能组合成当前1;那么对于每一个1,我们先判断小于当前1的数之和是否大于等于当前1代表的val,如果是的,直接选取即可,如果不是,再找当前位置1的数组有没有在原数组中出现,如果有则取它,否则就需要对更前面的1进行拆分。

代码
class Solution {
    public int minOperations(List<Integer> nums, int target) {
        var sb = new StringBuilder();
        while(target != 0) {
            if ((target & 1) == 1) {
                sb.append(1);
            } else {
                sb.append(0);
            }
            target >>= 1;
        }
        char[] chars = sb.toString().toCharArray();
        var map = new HashMap<Integer, Integer>();
        int ans = 0;
        for (var num : nums) {
            int bit = 0;
            while (num != 1) {
                num >>= 1;
                bit++;
            }
            map.merge(bit, 1, Integer::sum);
            ans = Math.max(ans, bit);
        }
        var cnt = new int[Math.max(ans, chars.length) + 5];
        for (int i = 0; i <= ans; i++) {
            cnt[i] = map.getOrDefault(i, 0);
        }
        ans = 0;
        int pre = 0, bit = 1;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '1') {
                if (pre >= bit) {
                    pre -= bit;
                } else {
                    int p = find(i, cnt);
                    if (p == -1) {
                        return -1;
                    }
                    ans += p;
                }
            }
            pre += cnt[i] * bit;
            bit <<= 1;
        }
        return ans;
    }

    private int find(int id, int[] cnt) {
        int ans = -1;

        for (int i = id; i < cnt.length; i++) {
            if (cnt[i] > 0) {
                cnt[i]--;
                for (int j = id; j < i; j++) {
                    cnt[j]++;
                }
                ans = i - id;
                break;
            }
        }
        return ans;
    }
}

D题

题意

选择一个id,id传k次之后的值最大。

思路

树上倍增板子题。

代码
class Solution {
    public long getMaxFunctionValue(List<Integer> receiver, long k) {
        var fa = new int[receiver.size()][log2(k) + 1];
        var sum = new long[receiver.size()][log2(k) + 1];
        for (int i = 0; i < receiver.size(); i++) {
            fa[i][0] = receiver.get(i);
            sum[i][0] = fa[i][0];
        }
        for (int j = 1; j < fa[0].length; j++) {
            for (int i = 0; i < fa.length; i++) {
                int pa = fa[i][j - 1];
                fa[i][j] = fa[pa][j - 1];
                sum[i][j] = sum[i][j - 1] + sum[pa][j - 1];
            }
        }

        long max = 0;
        for (int i = 0; i < receiver.size(); i++) {
            long k1 = k;
            long ans = i;
            int node = i;
            while(k1 != 0) {
                var len = Long.numberOfTrailingZeros(k1);
                ans += sum[node][len];
                node = fa[node][len];
                k1 &= (k1 - 1);
            }
            max = Math.max(max, ans);
        }
        return max;
    }

    public int log2(long n) {
        return (int) (Math.log10(n) / Math.log10(2));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值