您现在的位置是:主页 > news > 鹿泉微信网站建设/怎么做网络宣传推广
鹿泉微信网站建设/怎么做网络宣传推广
admin2025/4/25 19:29:45【news】
简介鹿泉微信网站建设,怎么做网络宣传推广,重庆网站备案系统,油漆网站设计LeetCode中与Permutations相关的共有四题: 31. Next Permutation 46. Permutations 47. Permutations II 60. Permutation Sequence 大致包括了所有全排列问题可能考到的题型。 本文按序列出了解这四道题的详细思路和AC代码。在各题之间&am…
LeetCode中与Permutations相关的共有四题:
31. Next Permutation
46. Permutations
47. Permutations II
60. Permutation Sequence
大致包括了所有全排列问题可能考到的题型。
本文按序列出了解这四道题的详细思路和AC代码。在各题之间,尽可能地使用了不同的解法,使大家对各种方法能有个了解。
目录
- 下一个全排列数
- 题一描述
- 题一解析
- 题一Java解答
- 无重复数字的全排列数
- 题二描述
- 题二解析
- 题二Java解答
- 有重复数字的全排列数
- 题三描述
- 题三解析
- 题三Java解答
- 取特定位置的全排列字符串
- 题四描述
- 题四解析
- 题四Java解答
下一个全排列数
题一描述:
原题链接:31. Next Permutation
给定任一非空正整数序列,生成这些数所能排列出的下一个较大序列。若给出的序列为最大序列,则生成最小序列。
输入 → 输出
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
- 1
- 2
- 3
- 4
- 5
题一解析:
概念:
这里,先考虑一个序列的最大最小情况。当一个序列为非递减序列时,它必然是该组数的最小的排列数;同理,当一个序列为非递增序列时,它必然是该组数的最大的排列数。
举例:
那么给定一个p(n)要如何才能生成p(n+1)呢?先来看下面的例子:
我们用
结论:
由此,我们可以知道,本题的关键即是求出数组末尾的最长的非递增子序列。
不妨假设在数组nums中,nums[k+1]…nums[n]均满足前一个元素大于等于后一个元素,即这一子序列非递增。
那么,我们要做的,就是把nums[k]与其后序列中稍大于nums[k]的数交换,接着再逆序nums[k+1]…nums[n]即可。
都是从n-1向前找:
上一个排列就是找前边大于后边的;交换
下一个排列找后边大于前面的;交换;
题一Java解答:
public class Solution {public void nextPermutation(int[] nums) {int len = nums.length;if (len<2) return ;int[] res = new int [len];/* 从倒数第二个元素开始,从后向前,找到第一个满足(后元素>前元素)的情况* 此时,记录前元素下标k,则[k+1,n-1]为一个单调非增子序列* 那么,这里只需要将一个比nums[k]大的最小数与nums[k]交换*/int lastEle = nums[len-1];int k = len-2;for (; k>=0; k--){if (lastEle > nums[k]) break;else {lastEle = nums[k];continue;}}// 当前排列为最大排列,逆序之if (k<0) {for (int i=0; i<(len+1)/2; i++) {swap(nums, i, len-1-i);}} else {// 在nums[k+1,n-1]中寻找大于nums[k]的最小数int index=0;for (int i=len-1; i>k; i--) {if (nums[i]>nums[k]) {swap(nums, i, k);index=i;break;}}// index为0,表示当前nums[k]小于其后任意一个数,直接交换k与len-1if (index==0){swap(nums, k, len-1);}// 将nums[k+1,n-1]逆序for (int i=k+1; i<(k+len+2)/2; i++) {swap(nums, i, k+len-i);}}return ;}// 交换元素public void swap(int[] nums, int i, int j){int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
无重复数字的全排列数
题二描述:
原题链接:46. Permutations
给定一个无重复数字的序列,返回这些数所能排列出所有序列。
样例输入:
[1,2,3]样例输出:
[ [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
题二解析:
这是很经典的全排列问题,本题的解法很多。因为这里的所有数都是相异的,故笔者采用了交换元素+DFS的方法来求解。
下面列出我的AC代码。代码中附有中文注释,在此就不再赘述具体步骤。
题二Java解答:
public class Solution {// 最终返回的结果集List<List<Integer>> res = new ArrayList<List<Integer>>();public List<List<Integer>> permute(int[] nums) {int len = nums.length;if (len==0||nums==null) return res;// 采用前后元素交换的办法,dfs解题exchange(nums, 0, len);return res;}public void exchange(int[] nums, int i, int len) {// 将当前数组加到结果集中if(i==len-1) {List<Integer> list = new ArrayList<>();for (int j=0; j<len; j++){list.add(nums[j]);}res.add(list);return ;}// 将当前位置的数跟后面的数交换,并搜索解for (int j=i; j<len; j++) {swap(nums, i, j);exchange(nums, i+1, len);swap(nums, i, j);}}public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
有重复数字的全排列数
题三描述:
原题链接:47. Permutations II
给定一个含有重复数字的序列,返回这些数所能排列出的所有不同的序列。
样例输入:
[1,1,2]样例输出:
[[1,1,2],[1,2,1],[2,1,1]
]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
题三解析
题意:
本题与题二略有不同,给定的序列中含有重复元素,需要返回这些数所能排列出的所有不同的序列集合。
思路:
这里我们先考虑一下,它与第二题唯一的不同在于:在DFS函数中,做循环遍历时,如果与当前元素相同的一个元素已经被取用过,则要跳过所有值相同的元素。
举个例子:对于序列<1,1,2,3>。在DFS首遍历时,1 作为首元素被加到list中,并进行后续元素的添加;那么,当DFS跑完第一个分支,遍历到1 (第二个)时,这个1 不再作为首元素添加到list中,因为1 作为首元素的情况已经在第一个分支中考虑过了。
为了实现这一剪枝思路,有了如下的解题算法。
解题算法:
1. 先对给定的序列nums进行排序,使得大小相同的元素排在一起。
2. 新建一个used数组,大小与nums相同,用来标记在本次DFS读取中,位置i的元素是否已经被添加到list中了。
3. 根据思路可知,我们选择跳过一个数,当且仅当这个数与前一个数相等,并且前一个数未被添加到list中。
根据以上算法,对题二的代码略做修改,可以得到如下的AC代码。
(在处理一般性问题时,建议用此算法,毕竟题二只是特殊情况)
题三Java解答
public class Solution {List<List<Integer>> res = new ArrayList<List<Integer>>();public List<List<Integer>> permuteUnique(int[] nums) {int len = nums.length;if(len==0||nums==null) return res;boolean[] used = new boolean[len];List<Integer> list = new ArrayList<Integer>();Arrays.sort(nums);dfs(nums, used, list, len);return res;}public void dfs(int[] nums, boolean[] used, List<Integer> list, int len) {if(list.size()==len) {res.add(new ArrayList<Integer>(list));return ;}for (int i=0; i<len; i++) {// 当前位置的数已经在List中了if(used[i]) continue;// 当前元素与其前一个元素值相同 且 前元素未被加到list中,跳过该元素if(i>0 && nums[i]==nums[i-1] && !used[i-1]) continue;// 深度优先搜索遍历used[i]=true;list.add(nums[i]);dfs(nums, used, list, len);list.remove(list.size()-1);used[i]=false;}}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
取特定位置的全排列字符串
题四描述:
原题链接:60. Permutation Sequence
给定正整数n和k,要求返回在[1,2,…,n]所有的全排列中,第k大的字符串序列。
样例输入:
3 4样例输出:
"231"
- 1
- 2
- 3
- 4
- 5
- 6
题四解析:
思路:
这里我们先考虑一个特殊情况,当n=4时,序列为[1,2,3,4],有以下几种情况:
“1+(2,3,4)的全排列”
“2+(1,3,4)的全排列”
“3+(1,2,4)的全排列”
“4+(1,2,3)的全排列”
我们已经知道,对于n个数的全排列,有n!种情况。所以,3个数的全排列就有6种情况。
如果我们这里给定的k为14,那么它将会出现在:
“3+(1,2,4)的全排列”
这一情况中。
我们可以程式化地得到这个结果:取k=13(从0开始计数),(n-1)!=3!=6,k/(n-1)!=2,而3在有序序列[1,2,3,4]中的索引就是2。
同理,我们继续计算,新的k=13%6=1,新的n=3,那么1/(n-1)!=2/2=0。在序列[1,2,4]中,索引0的数是1。那么,此时的字符串为”31”。
继续迭代,新的k=1%2=1,新的n=2,那么k/(n-1)!=1/1=1。在序列[2,4]中,索引为1的数是4。那么,此时的字符串为”314”。最后在串尾添上仅剩的2,可以得到字符串”3142”。
经过验算,此串确实是序列[1,2,3,4]的全排列数中第14大的序列。
解题算法:
1. 创建一个长度为n 的数组array,存放对应下标n的阶乘值。
2. 再新建一个长度为n 的数组nums,初始值为nums[i]=i+1,用来存放待选的字符序列。
3. 将得到的k减1后,开始迭代。迭代的规则是:迭代n次,每次选nums数组中下标为k/(n-1)!的数放在字符串的末尾,新的k=k%(n-1)!,新的n=n-1。
4. 最后,返回得到的字符串。
根据以上算法,可以得到如下的AC代码。
题四Java解答:
public class Solution {public String getPermutation(int n, int k) {StringBuilder sb = new StringBuilder();int[] array = new int[n+1];int sum = 1;array[0] = 1;// array[] = [1, 1, 2, 6, 24, ... , n!]for (int i=1; i<=n; i++){sum *= i;array[i] = sum;}// nums[] = [1, 2, 3, ... n]List<Integer> nums = new LinkedList<>();for (int i=0; i<n; i++){nums.add(i+1);}k--;for (int i=1; i<=n; i++){int index = k / array[n-i];sb.append("" + nums.get(index));nums.remove(index);k = k % array[n-i];}return sb.toString();}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
行文仓促,文中如有不足或不当之处,欢迎拍砖指正。转载请注明出处。