内容介绍
完整代码
void swap(int *a, int *b) {
int t = *a;
*a = *b, *b = t;
}
void reverse(int *nums, int left, int right) {
while (left < right) {
swap(nums + left, nums + right);
left++, right--;
}
}
void nextPermutation(int *nums, int numsSize) {
int i = numsSize - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = numsSize - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums + i, nums + j);
}
reverse(nums, i + 1, numsSize - 1);
}
思路详解
-
swap函数:这是一个辅助函数,用于交换两个整数的值。它接收两个整数的指针作为参数,通过临时变量
t
来实现两个整数的交换。 -
reverse函数:这是一个辅助函数,用于反转数组中指定范围的元素。它接收数组的指针、左边界索引和右边界索引作为参数。通过头尾元素交换的方式,将数组指定范围内的元素进行反转。
-
nextPermutation函数:这是主函数,用于生成给定数组的下一个排列。以下是详细步骤:
a. 从后向前查找第一个相邻升序的元素对(即找到第一个
nums[i] < nums[i + 1]
的位置)。如果不存在这样的元素对,说明当前数组是最大的排列,直接反转整个数组即可得到最小的排列。b. 在步骤a找到的元素
nums[i]
之后,从后向前查找第一个大于nums[i]
的元素nums[j]
。c. 交换
nums[i]
和nums[j]
的值。d. 反转
nums[i + 1]
到nums[numsSize - 1]
的元素,使得这部分元素按升序排列。
下面通过一个示例来具体说明这个过程:
假设数组为:1 2 3 4 3 2 1
步骤a:从后向前查找,找到nums[3] = 4
和nums[4] = 3
,满足nums[i] < nums[i + 1]
,因此i = 3
。
步骤b:在nums[i + 1]
到nums[numsSize - 1]
范围内,找到第一个大于nums[i]
的元素,即nums[6] = 1
。
步骤c:交换nums[3]
和nums[6]
,数组变为:1 2 3 1 3 2 4
。
步骤d:反转nums[4]
到nums[6]
的元素,数组变为:1 2 3 1 2 3 4
。
最终得到的数组1 2 3 1 2 3 4
就是原数组1 2 3 4 3 2 1
的下一个排列。
知识点精炼
一、指针与地址操作
- 指针:一种特殊变量,用于存储变量地址。
- 解引用:通过指针访问其所指向的变量,使用操作符
*
。
二、函数定义与调用
- 函数定义:使用
return_type function_name(parameters)
语法声明函数。 - 函数参数:通过指针传递地址,实现对原始数据的修改。
三、数组操作
- 数组元素访问:通过索引和指针运算访问数组元素。
- 数组区间操作:通过循环和指针操作实现对数组的区间操作。
四、算法逻辑
- 排列生成:通过交换和反转操作生成数组的下一个排列。
- 双指针技巧:使用两个指针分别从前后遍历数组,提高查找效率。
五、循环与条件判断
- while 循环:在不确定循环次数时,使用 while 循环实现条件控制。
- if-else 判断:根据条件执行不同的代码块。
六、代码优化
- 代码简洁性:通过逗号表达式和简洁的赋值语句减少代码行数。
- 减少不必要的操作:在循环和条件判断中,尽量减少不必要的计算和比较。
以下是具体知识点与代码的对应关系:
swap
函数:涉及指针解引用和临时变量交换。reverse
函数:使用双指针技巧,通过头尾元素交换实现数组反转。nextPermutation
函数:实现排列生成的算法逻辑,包括查找降序对、交换元素和反转数组区间。