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 ...
随机推荐
- HPU 第三次积分赛:阶乘之和(水题)
阶乘之和 描述 对于整数pp,给出以下定义 p=x_{1}!+x_{2}!+x_{3}!+...+x_{q}!(x_{i}<x_{j}for\ all\ i<j )p=x1!+x2!+ ...
- HDU 2544:最短路
最短路 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Codeforces Round #462 (Div. 2) B-A Prosperous Lot
B. A Prosperous Lot time limit per test 1 second memory limit per test 256 megabytes input standard ...
- CTF-练习平台-Misc之 又是一张图片,还单纯吗??
四.又是一张图片,还单纯吗?? 经过前面的方法尝试后都没有发现flag,尝试另一种方法“图片隐藏文件分离”,打开虚拟机,运行kali,使用里面的一个工具binwalk 首先将图片拖到kali的桌面上, ...
- 《DSP using MATLAB》Problem 3.12
- LG1600 天天爱跑步
题意 分析 对一个(s,t)查询,令f=lca(s,t),则操作可化为(s,f),(f,t). 考虑观察到的情况,若x在s到t的路径上,且x观察到,则 \[ \textrm{dep}_s-\textr ...
- java企业级开发的实质就是前台后台如何交互的-各个对象之间如何交互,通信的-程序执行的流程是怎样的
1.开山鼻祖-servlet 如何将url 和 strvlet(.java文件)联系起来的 顺平说的:在xml中,url先找到xml,由对应的url的得到servlet那个类,然后就可以输入一个网址访 ...
- 01.ubuntu16.06编译安装Hi3518EV200 SDK
转载,侵删 HI3518EV200 SDK安装并编译osdr. 1.开发环境 windows10电脑 + 虚拟机14 Pro + Ubuntu16.0.4 2.拷贝并解压.将 Hi3518E_SDK_ ...
- Hadoop通过路径和和链接访问HDFS
如果既想在Hadoop服务器本地可以通过绝对路径如"/user/hadoop"方式访问hdfs,也想通过"hdfs://local host:9000/user/hado ...
- Bootstrap:百科
ylbtech-Bootstrap:百科 Bootstrap (Web框架) Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.Java ...