【贪心 从一般到特殊】3644. 排序排列|1775
本文涉及知识点
C++贪心
LeetCode3644. 排序排列
给你一个长度为 n 的整数数组 nums,其中 nums 是范围 [0…n - 1] 内所有数字的一个 排列 。
你可以在满足条件 nums[i] AND nums[j] == k 的情况下交换下标 i 和 j 的元素,其中 AND 表示按位与操作,k 是一个非负整数。
返回可以使数组按 非递减 顺序排序的最大值 k(允许进行任意次这样的交换)。如果 nums 已经是有序的,返回 0。
排列 是数组所有元素的一种重新排列。
示例 1:
输入:nums = [0,3,2,1]
输出:1
解释:
选择 k = 1。交换 nums[1] = 3 和 nums[3] = 1,因为 nums[1] AND nums[3] == 1,从而得到一个排序后的排列:[0, 1, 2, 3]。
示例 2:
输入:nums = [0,1,3,2]
输出:2
解释:
选择 k = 2。交换 nums[2] = 3 和 nums[3] = 2,因为 nums[2] AND nums[3] == 2,从而得到一个排序后的排列:[0, 1, 2, 3]。
示例 3:
输入:nums = [3,2,1,0]
输出:0
解释:
只有当 k = 0 时,才能进行排序,因为没有更大的 k 能够满足 nums[i] AND nums[j] == k 的交换条件。
提示:
1<=n==nums.length<=1051 <= n == nums.length <= 10^51<=n==nums.length<=105
0 <= nums[i] <= n - 1
nums 是从 0 到 n - 1 的一个排列。
错误解法:有向图
如果i == nums[i],则增加自环。
否则增加有向边i→nums[i]i \rightarrow nums[i]i→nums[i],由于出度入度都是1,故每个联通区域是环。
性质一:任意非自环点i,如果某位为0,则k的此位一定不是1。否则i无法和任意点联通。
性质二:所有非自环点,某位全为1,则k的此位一定不是0。否则所有点都无法和其它点联通。
按性质一二计算k后验算,如果非法返回-1。
实现
k是所有非自环点的与和。
已经有序无序特殊处理,k默认0.
错误原因
不需要最少交换次数。
正确解法
性质一:k==0时一定能够交换。需要交换的数,通过nums[0]中转。
性质二:按错误解法求的k,是解。通过nums[k]中转。下面来证明最优解:
某非自环点,某位是0,则k此位不能是1。否则此点不和任意点联通。
代码
核心代码
class Solution {public:int sortPermutation(vector<int>& nums) {int k = INT_MAX;for (int i = 0; i < nums.size(); i++) {if (i == nums[i]) { continue; }k &= i;}return (INT_MAX==k)?0:k;}};
