携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,下一个排列[发挥主观能动性发现规律] - 掘金 (juejin.cn)
前言
充分发挥主观能动性,找到题的个性所在,挖掘其特点,见招拆招,没有死板的套路,需要什么就用代码的分支/循环/递归/数据结构来完成即可。
一、下一个排列
二、逻辑分析与代码整理
package everyday.medium;
// 下一个排列
public class NextPermutation {
/*
target:把nums整体当作一个数,这些数字不变,取下一个要求比原数大的组合。
core:什么时比原来大的组合?寻找问题个性所在,其实从后往前找到一个非递增的数,然后把后面刚好比它大的数和其交换,再翻转后面的数即可。
注:如果遍历完都没找到,那就是特殊情况,直接翻转。
*/
public void nextPermutation(int[] nums) {
if (nums.length == 1) return;
// 寻找非递增的那个数的idx,为了后面的交换。
int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) --i;
int begin = 0;//翻转开始处,默认全部翻转。
// 当i >= 0时,需要确定新的翻转开始处。
if (i >= 0) {
// 寻找需要交换的数字
int idx = nums.length - 1;
while (nums[idx] <= nums[i]) idx--;
// 交换两者,且 i + 1 到 nums.length - 1保持单调递减,直接翻转。
swap(nums, i, idx);
// 确定从那里开始翻转
begin = i + 1;
}
// 翻转
reverse(nums, begin, nums.length);
}
public void reverse(int[] nums, int left, int right) {
int mid = right - left >>> 1;
for (int j = 0; j < mid; j++) {
int t = nums[left + j];
nums[left + j] = nums[right - 1 - j];
nums[right - 1 - j] = t;
}
}
// 交换两数。
public void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}
总结
1)发挥主观能动性/思考力,发现问题个性,按逻辑写出代码,再整理逻辑代码。
参考文献
[1] LeetCode 下一个排列