leetcode 3266. K 次乘运算后的最终数组 II
给你一个整数数组 nums
,一个整数 k
和一个整数 multiplier
。
你需要对 nums
执行 k
次操作,每次操作中:
- 找到
nums
中的 最小 值x
,如果存在多个最小值,选择最 前面 的一个。 - 将
x
替换为x * multiplier
。
k
次操作以后,你需要将 nums
中每一个数值对 109 + 7
取余。
请你返回执行完 k
次乘运算以及取余运算之后,最终的 nums
数组。
示例 1:
输入:nums = [2,1,3,5,6], k = 5, multiplier = 2
输出:[8,4,6,5,6]
解释:
操作 | 结果 |
---|---|
1 次操作后 | [2, 2, 3, 5, 6] |
2 次操作后 | [4, 2, 3, 5, 6] |
3 次操作后 | [4, 4, 3, 5, 6] |
4 次操作后 | [4, 4, 6, 5, 6] |
5 次操作后 | [8, 4, 6, 5, 6] |
取余操作后 | [8, 4, 6, 5, 6] |
示例 2:
输入:nums = [100000,2000], k = 2, multiplier = 1000000
输出:[999999307,999999993]
解释:
操作 | 结果 |
---|---|
1 次操作后 | [100000, 2000000000] |
2 次操作后 | [100000000000, 2000000000] |
取余操作后 | [999999307, 999999993] |
提示:
1 <= nums.length <= 104
1 <= nums[i] <= 109
1 <= k <= 109
1 <= multiplier <= 106
解题思路
快速幂
因为和坐标有关系,先定义以下变量
设置了一个node节点来存储元素的值value和对应的坐标index
获取最大值max
数组的长度length
这道题可以分以下思路
1.先把节点排序,在不超过最大值的情况下,和操作次数不超过k的情况下,用优先队列直接操作。复杂度不会超过32 * length。
2.当前的数组中,因为每一个元素 value * m >= max, 所以可以这么说,当操作 length 次的时候,就会是每个数字都会被操作一次.
可以用反证法来证明,若是不是每个数字都会被操作一次,那肯定是最大值没有操作, 但是每个值 value * m >= max 所以,操作 length - 1次的时候,所有的值,都比max大了,那么,max一定能被操作。
3.剩下的次数k中, 就会分为两部分,分别对length取商得到t1,对length取模得到t2
4.对于t2的操作,因为会小于length, 所以可以和步骤一 一样操作。
5.对于t1的操作,根据步骤二的理论,就相当于每个元素都会 * t1, 所以可以用快速幂来解答。
public int[] getFinalState(int[] nums, int k, int m) { if (m == 1) { return nums; } int length = nums.length; Node[] nodes = new Node[length]; int max = 0; for (int i = 0; i < length; i++) { nodes[i] = new Node(nums[i], i); max = Math.max(max, nums[i]); } int v = getList(nodes, k, m, max); if (v == k) { for (Node node : nodes) { nums[node.index] = (int) (node.value % 1000000007); } return nums; } k -= v; int t1 = k / length; int t2 = k % length; getList(nodes, t2, m); int mm = mm(m, t1); // System.out.println(v + " " + t1 + " " + t2 + " " + mm); for (Node node : nodes) { nums[node.index] = (int) (node.value * mm % 1000000007); } return nums; } public int mm(int m, int t1) { long item = m; long sum = 1; while (t1 != 0) { if ((t1 & 1) == 1) { sum = sum * item % 1000000007; } item = item * item % 1000000007; t1 >>= 1; } return (int) sum; } private int getList(Node[] nodes, int k, int m, int max) { int count = 0; PriorityQueue<Node> queue = new PriorityQueue<>((a, b) -> a.value == b.value ? Integer.compare(a.index, b.index) : Long.compare(a.value, b.value)); Collections.addAll(queue, nodes); while (queue.peek().value * m <= max) { Node poll = queue.poll(); poll.value = poll.value * m ; queue.add(poll); count++; if (count == k) { break; } } return count; } private void getList(Node[] nodes, int k, int m) { int count = 0; PriorityQueue<Node> queue = new PriorityQueue<>((a, b) -> a.value == b.value ? Integer.compare(a.index, b.index) : Long.compare(a.value, b.value)); Collections.addAll(queue, nodes); while (count < k) { Node poll = queue.poll(); poll.value = poll.value * m ; queue.add(poll); count++; } for (Node node : nodes) { node.value = node.value % 1000000007; } } private static class Node { private long value; private int index; public Node(long value, int index) { this.value = value; this.index = index; } }