第16章 模拟
大约 2 分钟
第16章 模拟
下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须** 原地 **修改,只允许使用额外常数空间。
标准的“下一个排列”算法可以描述为:
- 从后向前查找第一个相邻升序的元素对
(i,j)
,满足A[i] < A[j]
。此时[j,end)
必然是降序- 在
[j,end)
从后向前查找第一个满足A[i] < A[k]
的k
。A[i]
、A[k]
分别就是上文所说的「小数」、「大数」- 将
A[i]
与A[k]
交换- 可以断定这时
[j,end)
必然是降序,逆置[j,end)
,使其升序- 如果在步骤 1 找不到符合的相邻元素对,说明当前
[begin,end)
为一个降序顺序,则直接跳到步骤 4该方法支持数据重复,且在 C++ STL 中被采用。
class Solution {
public void nextPermutation(int[] nums) {
if(nums.length == 1){
return;
}
int i = nums.length - 2;
for(; i >= 0 && nums[i] >= nums[i + 1]; i--);
if(i == -1){
reverse(nums, 0, nums.length - 1);
}else{
int j = nums.length - 1;
for(; nums[i] >= nums[j]; j--);
swap(nums, i, j);
reverse(nums, i + 1, nums.length - 1);
}
}
private void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private void reverse(int[] nums, int i, int j){
while(i < j){
swap(nums, i, j);
i++;
j--;
}
}
}
区间问题
LC57:插入区间
给你一个 无重叠的 *,*按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例:
输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
if (intervals == null || intervals.length == 0) {
return new int[][]{{newInterval[0], newInterval[1]}};
}
List<int[]> list = new ArrayList<>();
int index = 0;
// 步骤一:找到需要合并的区间
while (index < intervals.length && intervals[index][1] < newInterval[0]) {
list.add(intervals[index++]);
}
// 步骤二:合并区间
while (index < intervals.length && intervals[index][0] <= newInterval[1]) {
newInterval[0] = Math.min(newInterval[0], intervals[index][0]);
newInterval[1] = Math.max(newInterval[1], intervals[index][1]);
index++;
}
list.add(newInterval);
// 步骤三:处理合并区间之后的区间
while (index < intervals.length) {
list.add(intervals[index++]);
}
return list.toArray(new int[list.size()][]);
}
}
Loading...