6990. Account Balance After Rounded Purchase

一开始,你的银行账户里有 100 块钱。

给你一个整数purchaseAmount ,它表示你在一次购买中愿意支出的金额。

在一个商店里,你进行一次购买,实际支出的金额会向 最近 的 10 的 倍数 取整。换句话说,你实际会支付一个 非负 金额 roundedAmount ,满足 roundedAmount 是 10 的倍数且 abs(roundedAmount - purchaseAmount) 的值 最小 。

如果存在多于一个最接近的 10 的倍数,较大的倍数 是你的实际支出金额。

请你返回一个整数,表示你在愿意支出金额为 purchaseAmount 块钱的前提下,购买之后剩下的余额。

注意: 0 也是 10 的倍数。

测试样例

输入:purchaseAmount = 9

输出:9

解释:这个例子中,最接近 9 的 10 的倍数是 10 。所以你的账户余额为 100 - 10 = 90 。

解答:按照题意10的倍数做一下取整。

class Solution {
    public int accountBalanceAfterPurchase(int purchaseAmount) {
        int remain = 100 - purchaseAmount;
        int r = remain / 10, o = r + 1;
        if (remain - r * 10 <= o * 10 - remain) {
            return r * 10;
        } else {
            return o * 10;
        }
    }
}

6940. Insert Greatest Common Divisors in Linked List

给你一个链表的头 head ,每个结点包含一个整数值。

在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。

请你返回插入之后的链表。

两个数的 最大公约数 是可以被两个数字整除的最大正整数。

测试样例:

输入:head = [7]

输出:[7]

解释:

没有相邻结点,所以返回初始链表。

解答: 考察最小公约数的计算与链表遍历。

class Solution {
    public ListNode insertGreatestCommonDivisors(ListNode head) {
        ListNode res = head, cur = head, next = head.next;
        while (next != null) {
            ListNode add = new ListNode(gcd(cur.val, next.val));
            cur.next = add;
            add.next = next;
            cur = next;
            next = next.next;
        }
        return res;
    }

    private int gcd(int x, int y) {
        while (y != 0) {
            int tmp = x % y;
            x = y;
            y = tmp;
        }
        return x;
    }
}

6956. Minimum Seconds to Equalize a Circular Array

给你一个下标从 0 开始长度为 n 的数组 nums 。

每一秒,你可以对数组执行以下操作:

  • 对于范围在 [0, n - 1] 内的每一个下标 i ,将 nums[i] 替换成 nums[i] ,nums[(i - 1 + n) % n] 或者 nums[(i + 1) % n] 三者之一。

注意,所有元素会被同时替换。

请你返回将数组 nums 中所有元素变成相等元素所需要的 最少 秒数

测试样例:

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

输出:1

解释:

我们可以在 1 秒内将数组变成相等元素:

  • 第 1 秒,将每个位置的元素分别变为 [nums[3],nums[1],nums[3],nums[3]] 。变化后,nums = [2,2,2,2] 。

1 秒是将数组变成相等元素所需要的最少秒数。

解答: 这道题目有点脑筋急转弯。选定一个数字之后,那么就可以计算数组中每个数字到达最近选定数字的距离。因为提示给的范围还是比较大的1 <= n == nums.length <= 10^5,不能直接使用暴力算法。所以就把数组按照数字聚合,并记录一下位置。利用一下数学公式可以快速计算出到达选定数字的最短距离。

class Solution {
    public int minimumSeconds(List<Integer> nums) {
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        int offset = 0;
        for (int n : nums) {
            if (!map.containsKey(n)) {
                map.put(n, new ArrayList<>());
            }
            map.get(n).add(offset++);
        }

        int res = Integer.MAX_VALUE;
        for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
            List<Integer> pos = entry.getValue();
            int internal = (nums.size() - (pos.get(pos.size() - 1) - pos.get(0))) / 2;
            for (int i = 1; i < pos.size(); ++i) {
                int diff = (pos.get(i) - pos.get(i - 1));
                internal = Math.max(internal, diff / 2);
            }
            res = Math.min(res, internal);
        }
        return res;
    }
}

6987. Minimum Time to Make Array Sum At Most x

给你两个长度相等下标从 0 开始的整数数组 nums1 和 nums2 。每一秒,对于所有下标 0 <= i < nums1.length ,nums1[i] 的值都增加 nums2[i] 。操作 完成后 ,你可以进行如下操作:

  • 选择任一满足 0 <= i < nums1.length 的下标 i ,并使 nums1[i] = 0 。

同时给你一个整数 x 。

请你返回使 nums1 中所有元素之和 小于等于 x 所需要的 最少 时间,如果无法实现,那么返回 -1 。

测试样例:

输入:nums1 = [1,2,3], nums2 = [1,2,3], x = 4

输出:4

第 1 秒,我们对 i = 0 进行操作,得到 nums1 = [0,2+2,3+3] = [0,4,6] 。
第 2 秒,我们对 i = 1 进行操作,得到 nums1 = [0+1,0,6+3] = [1,0,9] 。
第 3 秒,我们对 i = 2 进行操作,得到 nums1 = [1+1,0+2,0] = [2,2,0] 。
现在 nums1 的和为 4 。不存在更少次数的操作,所以我们返回 3 。

解答: 如果n秒之后,理想的选择能够让数组满足要求,我们就可以停止计算。然后需要思考到,我们最多进行nums1.length次操作(这个时候,所有nums1中的数字都清零了,之后的操作无法减去更多的数字了)。其次还有一个需要思考到,同一个位置最多进行一次操作。否则假设一个位置进行了2次操作,t1和t2。那么t1的那一次操作本质上是没有意义的,只要进行t2的操作就可以了。t1的操作可以让给别的位置以求最大化。

最后我们需要知道理想的选择是如何选择,利用动态规划可以计算出当前位置的最佳选择方案。

class Solution {
    public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {
        nums1 = buildArr(nums1);
        nums2 = buildArr(nums2);
        long sum1 = getSum(nums1), sum2 = getSum(nums2);
        if (sum1 <= x) {
            return 0;
        }

        int len = nums1.size();
        Integer[] sort = new Integer[len];
        for (int i = 0; i < sort.length; ++i) {
            sort[i] = i;
        }

        List<Integer> finalNums = nums2;
        Arrays.sort(sort, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return finalNums.get(o1).compareTo(finalNums.get(o2));
            }
        });

        long[] mem = new long[len];
        for (long n = 1; n <= nums1.size(); ++n) {
            long[] nextMem = new long[len];
            long max = 0;
            for (int i = 0; i < len; ++i) {
                if (i == 0) {
                    nextMem[sort[i]] = nums1.get(sort[i]) + nums2.get(sort[i]) * n;
                } else {
                    nextMem[sort[i]] = Math.max(nextMem[sort[i - 1]],
                            mem[sort[i - 1]] + nums1.get(sort[i]) + nums2.get(sort[i]) * n);
                }
                max = Math.max(nextMem[sort[i]], max);
            }
            if (sum1 + sum2 * n - max <= x) {
                return (int)n;
            }
            mem = nextMem;
        }
        return -1;
    }

    private long getSum(List<Integer> nums) {
        long sum = 0;
        for (int n : nums) {
            sum += n;
        }
        return sum;
    }

    private List<Integer> buildArr(List<Integer> nums) {
        List<Integer> res = new ArrayList<>(nums);
        return res;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *