31. Next Permutation + 46. Permutations + 47. Permutations II + 60. Permutation Sequence
▶ 问题:字典序生成有关的问题。
▶ 31. 由当前序列生成字典序里的下一个序列。
● 初版代码,19 ms
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
int i, j, temp;
for (i = nums.size() - ; i > && nums[i - ] >= nums[i]; i--);// 从右向左寻找第一个递增对
if (!i) // i == 0,当前排序已经是最大的,全反序得到最小的
{
for (j = ; i < nums.size() / ; j++)
temp = nums[j], nums[j] = nums[nums.size() - - j], nums[nums.size() - - j] = temp;
return;
}
else if (i == nums.size() - ) // 最后两个元素就是递增对,交换他俩就行
{
temp = nums[i], nums[i] = nums[i - ], nums[i - ] = temp;
return;
}
for (j = nums.size() - ; j >= i && nums[j] <= nums[i - ]; j--);// 其他情形,需要在右侧递减部分中找到比递增较小元更大的第一个元素
temp = nums[i - ], nums[i - ] = nums[j], nums[j] = temp; // 将右侧较大的元素交换到递增对较小元的位置
for (j = i; j < (nums.size() + i) / ; j++) // 右侧进行反序
temp = nums[j],nums[j] = nums[nums.size() + i - - j],nums[nums.size() + i - - j] = temp;
return;
}
};
● 改进代码,15 ms,第二次查找时使用二分法改进,引入原数组长度的常量,引入内置交换函数 std::swap()。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
};
● 大佬的代码,13 ms,使用了排序函数
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, flag, index;
for (flag = , i = index = len - ; i > ; i--)
{
if (nums[i] <= nums[i - ])
index--;
else
{
for (int j = len - ; j >= index; j--)
{
if (nums[j] > nums[i - ])
{
swap(nums[i - ], nums[j]);
break;
}
}
sort(nums.begin() + i, nums.end());
flag = ;
break;
}
}
if (len && flag)
sort(nums.begin(), nums.end());
}
};
● 偷懒的代码,14 ms,直接使用内置函数 next_permutation(),该函数返回值是一个 bool 变量,仅当输入的数组引用是一个降序时返回 false,但此时仍然将数组调整为字典序的下一个(升序)。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
next_permutation(nums.begin(), nums.end());
return;
}
};
▶ 46. 生成给定元素的所有排列(元素无重复)
● 自己的代码,13 ms,反复调用第 31 题的结果来进行枚举。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
vector<vector<int>> permute(vector<int>& nums)
{
int count, i;
vector<vector<int>> output;
for (i = nums.size(), count = ; i > ; count *= i, i--); // 计算阶乘(总共排列数)
sort(nums.begin(),nums.end()); // 排序得到第一个排列
output.push_back(nums);
for (i = ; i < count; i++) // 每次循环生成下一个排列,不合并压入可以优化最后一次函数 nextPermutation()调用
{
nextPermutation(nums);
output.push_back(nums);
}
return output;
}
};
● 大佬的代码,13 ms,使用了内置函数 next_permutation()
class Solution
{
public:
vector<vector<int>> permute(vector<int>& nums)
{
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for (result.push_back(nums); next_permutation(nums.begin(), nums.end());)
result.push_back(nums);
return result;
}
};
▶ 47. 生成给定元素的所有排列(元素有重复)
● 自己的代码,26 ms,原数组排序后统计各重复部分的长度,计算重复排列数。由于前面 31 题中的程序在求“下一个排列”的时候已经跳过了重复的情形,所以只要恰当的减少该函数的调用次数就能列出所有含重复元素的排列。
class Solution
{
public:
void nextPermutation(vector<int>& nums)// 改进
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
inline int factorial(int a)// 阶乘函数
{
int i, output;
for (output = , i = ; i <= a; output *= i, i++);
return output;
}
vector<vector<int>> permuteUnique(vector<int>& nums)
{
int count, i, rep;
vector<vector<int>> output;
count = factorial(nums.size()); // 计算重复排列数
sort(nums.begin(), nums.end()); // 排序得到第一个排列
for (i = ; i < nums.size() - ; i++)
{
for (; i < nums.size() - && nums[i] != nums[i + ]; i++); // 跳过相邻项不同的部分
for (rep = ; i < nums.size() - && nums[i] == nums[i + ]; rep++, i++); // 记录本节中相邻项相同的个数
count /= factorial(rep + ); // 重复排列的计算
}
output.push_back(nums);
for (i = ; i < count; i++) // 每次循环生成下一个排列,不合并压入可以优化最后一次函数 nextPermutation()调用
{
nextPermutation(nums);
output.push_back(nums);
}
return output;
}
};
● 大佬的代码,30 ms,回溯,逐个寻找新排列。
class Solution
{
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
vector<vector<int>> result; // 存放结果
vector<int> flags(nums.size(), ), content;// flag[i] 表当前 nums[i] 是否被使用,content 为当前排列(填满就送入 reslut)
sort(nums.begin(), nums.end());
helper(nums, content, flags, result);
return result;
} void helper(vector<int>& nums, vector<int>& content, vector<int>& flags, vector<vector<int>>& result)
{
if (content.size() == nums.size())// 所有元素都被使用,将 content 中的排列放入 result 中
{
result.push_back(content);
return;
}
for (int i = ; i < nums.size(); i++)
{
if (i > && nums[i] == nums[i - ] && flags[i - ] != )// 跳过相同的元素
break;
if (!flags[i])// 元素 nums[i] 还没有被谁用过
{
flags[i] = ; // 把元素 nums[i] 添加到当前的排列末尾
content.push_back(nums[i]);
int i1 = i;
while (i < nums.size() - && nums[i + ] == nums[i])// 跳过相同元素
i++;
helper(nums, content, flags, result); // 尝试在添加了元素 nums[i] 以后继续添加下一个元素
content.pop_back(); // 去掉当前添加的元素,由于元素可能重复,所以需要在最后一个元素处标记未使用
flags[i1] = ;
}
}
}
};
● 大佬的代码改进,27 ms,基本算法相同。
class Solution
{
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
vector<vector<int>> result;
vector<bool> flags(nums.size(), true);
vector<int> content;
sort(nums.begin(), nums.end());
helper(nums, content, flags, result);
return result;
}
void helper(vector<int>& nums, vector<int>& content, vector<bool>& flags, vector<vector<int>>& result)
{
if (content.size() == nums.size())
{
result.push_back(content);
return;
}
int i, j;
for (i = ; i < nums.size(); i++)
{
if (flags[i])
{
flags[i] = false;
content.push_back(nums[i]);
for (j = i; i < nums.size() - && nums[i + ] == nums[i]; i++);
helper(nums, content, flags, result);
content.pop_back();
flags[j] = true;
}
}
}
};
▶ 60. 求给定元素字典序排列中的第 k 个。
● 初版,108 ms,逐个生成排列,直到第 k 个为止。
class Solution
{
public:
string getPermutation(int n, int k)
{
int i;
vector<int> table(n);
for (i = ; i < n; table[i] = i++);
for (i = ; i < k; i++)
next_permutation(table.begin(), table.end());
string output("");
for (i = ; i < n; i++)
output += table[i] + '';
return output;
}
};
● 改进版,6 ms,利用阶乘计算出所求排列,最快的解法算法与之相同。
class Solution
{
public:
string getPermutation(int n, int k)
{
int i, j;
string ret;
vector<int> factorial(n, );// 阶乘和字符的打表
vector<char> num(n, ); for (i = ; i < n; i++)
factorial[i] = factorial[i - ] * i;
for (i = ; i < n; i++)
num[i] = '' + (i + );
for (i = n, k--; i >= ; i--)
{
j = k / factorial[i - ];
k %= factorial[i - ];
ret.push_back(num[j]);
num.erase(num.begin() + j);
}
return ret;
}
};
31. Next Permutation + 46. Permutations + 47. Permutations II + 60. Permutation Sequence的更多相关文章
- [LeetCode] 47. 全排列 II
题目链接 : https://leetcode-cn.com/problems/permutations-ii/ 题目描述: 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [ ...
- Leetcode之回溯法专题-47. 全排列 II(Permutations II)
Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...
- [LeetCode] 47. Permutations II 全排列 II
Given a collection of numbers that might contain duplicates, return all possible unique permutations ...
- [Leetcode][Python]47: Permutations II
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 47: Permutations IIhttps://oj.leetcode. ...
- [leetcode] 47. Permutations II
Given a collection of numbers that might contain duplicates, return all possible unique permutations ...
- 47. Permutations II
题目: Given a collection of numbers that might contain duplicates, return all possible unique permutat ...
- Leetcode之回溯法专题-46. 全排列(Permutations)
Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...
- leetcode 46. 全排列 及 47. 全排列 II
46. 全排列 问题描述 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3 ...
- LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation]
LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation] <c++> LeetCode 31 Next Pe ...
随机推荐
- 结构体内的函数与bfs的情景变量
关于结构体内的函数,太难的尚且不会用,下面是一个简单一点的结构体内函数的代码 定义这样一个结构体函数之后就能像如下这样使用了 以上为结构体内的简单函数,下面重点来了,关于bfs找最短路由于需要避免走回 ...
- sleep和 wait
- PHP 中的对象传递
<?php class A { public $age = 0; public $username = ""; public $obj = null; } $a = new ...
- 【转】每天一个linux命令(53):route命令
原文网址:http://www.cnblogs.com/peida/archive/2013/03/05/2943698.html Linux系统的route命令用于显示和操作IP路由表(show / ...
- Oracle 表空间与数据文件
-============================== --Oracle 表空间与数据文件 --============================== /* 一.概念 表空间:是一个或多 ...
- junit 知识点
JUnit 测试框架具有以下重要特性: 测试工具 测试套件 测试运行器 测试分类 测试工具 测试工具是一整套固定的工具用于基线测试.测试工具的目的是为了确保测试能够在共享且固定的环境中运行,因此保证测 ...
- oracle 导入excel
方法二.利用PLSQL Developer使用PLSQL Developer工具,这个可是大名鼎鼎的Oracle DBA最常使用的工具.在单个文件不大的情况下(少于100000行),并且目的表结构已经 ...
- opencv中的缩放函数
图像处理里面缩放操作是比较常见的: 最近邻插值:类似简单映射的处理方式,目标图像w1,h1,原始图像w0,h0,则在目标图像上的点(x,y)的像素点实际对应原始图上(x*w0/w1,y*h0/h1)的 ...
- python处理excel(二):写
代码参考自zhoujie.函数接口可参考该blog. 基本的write函数接口很简单: 新建一个excel文件 file = xlwt.Workbook() (注意这里的Workbook首字母是大写) ...
- Number常用方法函数
Number类型应该是ECMAScript中最令人关注的数据类型了,这种类型使用IEEE754来表示整数和浮点数,并针对Number相关特点定义了一系列相关的方法函数. isFinite() 在Jav ...