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 ...
随机推荐
- 如何生成SPFILE文件
1.spfile是Oracle9i之后引入的,目的是提高系统安全性.在Oracle8i下初始化参数文件为文本文件,可以使用文本编辑器进行编辑,当需要修改初始化参数时,需要在init.ora文件中修改, ...
- FormData 知识点
通过FormData对象可以组装一组用 XMLHttpRequest发送请求的键/值对.它可以更灵活方便的发送表单数据,因此可以独立于表单使用. 如果你把表单的编码类型设置为multipart/for ...
- cookie 知识点
cookie失效是由浏览器实现的,根据时间来控制,服务器端并不做cookie是否失效的验证. 某个cookie失效了浏览器发送请求时便不会带上它,服务器端自然就没有这个cookie了,所以对于服务器来 ...
- telinit:Did not receive a reply.Possible causes include:the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired
问题: Enabling /etc/fstab swaps: [ok]telinit:Did not receive a reply.Possible causes include:the remot ...
- Word中回车和网页换行替换
回车^p 换行^l 用编辑中的查找替换即可 查找^l,替换为^p (一)有建议说按Delete键一个一个将其删除,这是麻烦的,其实可用WORD的查找替换工具一次性替换成回车符.查找--点特殊字符--手 ...
- POJ2411骨牌覆盖——状压dp
题目:http://poj.org/problem?id=2411 状压dp.注意一下代码中标记的地方. #include<iostream> #include<cstdio> ...
- python下爬某个网页的图片
#coding=utf-8 import re import urllib def getHtml(url): #获取url对应得源码 page = urllib.urlopen(url) html ...
- C#操作VFP的dbf数据库文件实例
C#操作VFP的dbf数据库文件实例 新一篇: js获取网站跟路径 实例中分别使用Oledb和Odbc操作vfp数据库dbf文件,操作包括:读取,增删改. 已测试可直接使用,使用方法:下面代码分两个部 ...
- PMP学习笔记
PMI:Project Management Institute,项目管理协会于1969年在美国成立,致力于全球范围内的项目管理研究.标准制定和出版.价值倡导.职业认证和学位 课程认证.现在,PMI已 ...
- asp.net 网站 发布时 去掉.cs文件
VS2013在WIN8下扁平的UI和我今天锈垢的大脑,让找这个设置找了好半天!!! OK,言归正传. 在要发布的网站上右键,选择"发布网站". 在发布窗口中,会让你选择 ...