▶ 问题:字典序生成有关的问题。

▶ 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的更多相关文章

  1. [LeetCode] 47. 全排列 II

    题目链接 : https://leetcode-cn.com/problems/permutations-ii/ 题目描述: 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [ ...

  2. Leetcode之回溯法专题-47. 全排列 II(Permutations II)

    Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...

  3. [LeetCode] 47. Permutations II 全排列 II

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  4. [Leetcode][Python]47: Permutations II

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 47: Permutations IIhttps://oj.leetcode. ...

  5. [leetcode] 47. Permutations II

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  6. 47. Permutations II

    题目: Given a collection of numbers that might contain duplicates, return all possible unique permutat ...

  7. Leetcode之回溯法专题-46. 全排列(Permutations)

    Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...

  8. leetcode 46. 全排列 及 47. 全排列 II

    46. 全排列 问题描述 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3 ...

  9. LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation]

    LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation] <c++> LeetCode 31 Next Pe ...

随机推荐

  1. js三级联动

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  2. java面试题12

    1.  jsp与servlet的区分? 答:Servlet和JSP都是基于java语言上的动态网页技术,Servlet程序其实就是java程序,只不过它所使用的类库为JAVA Servlet API, ...

  3. Android 第三方分享中遇到的问题以及解决方式

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/liuxian13183/article/details/36189343               ...

  4. [C++] Win32 API 的多线程Timer管理Trick - 利用PostThreadMessage

    有时候我们需要在程序里定时地完成一些任务, 比如5秒后发送, 10秒后弹窗之类的操作. 这就需要一个类似于定时器的组件. 这个组件在windows.h里被称为Timer. 设置一个Timer 第一步当 ...

  5. JUC集合之 CopyOnWriteArrayList

    CopyOnWriteArrayList介绍 它相当于线程安全的ArrayList.和ArrayList一样,它是个可变数组:但是和ArrayList不同的时,它具有以下特性: 它最适合于具有以下特征 ...

  6. JMeter和JMeterPlugin的下载安装

    JMeter和JMeterPlugin的下载安装 Apache Jmeter是一个100%的纯Java桌面应用,主要是针对web的压力和性能测试,但后来扩展到其他测试领域.Jmeter可以用于测试FT ...

  7. C#实现不安装Oracle客户端访问远程服务器数据

    概述: C#通过使用ADO的方式在未安装Oracle数据库的前提下,客户端程序远程访问服务器,会出现:“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或 ...

  8. 设计模式初学者笔记:Abstract Factory模式

    首先啰嗦下创建迷宫所用的Room类.这个类并不直接保存Room四周的构造,而是通过MapSite* _sides[4]这个私有数组成员指向Room四周的构造.那么什么时候将四周构造直接放在Room中, ...

  9. 论战大数据----胖子哥的PK之旅(一)

    胖子哥(1106110976) 9:35:36 http://www.cnblogs.com/hadoopdev/p/3531963.htmlnosqlt数据库-肖(380594863) 9:38:0 ...

  10. Spring Cloud config之一:分布式配置中心入门介绍

    Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持.配置服务器为各应用的所有环境提供了一个中心化的外部配置.它实现了对服务端和客户端对Spring Environm ...