【LeetCode】排序系列

31. Next Permutation

题目:找到给出序列的下一序列。

思路:分三步:一是从后往前找到非递增的位置,即需要开始交换的位置;二是在该位置之后找到第一个比它大的数,并与其交换;三是对后面的序列做一个逆序,然后返回。如果没有找到第一步的位置,就对整个数组逆序。

public class Solution {
    public void nextPermutation(int[] nums) {
        int len = nums.length;
        if(len < 2) return;
        for(int i = len-2; i >= 0; i--){
            if(nums[i+1] > nums[i]){
                for(int j = len-1; j > i; j--){
                    if(nums[j] > nums[i]){
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                        for(int k = 0; k < (len-1-i)/2; k++){
                            temp = nums[k+i+1];
                            nums[k+i+1] = nums[len-1-k];
                            nums[len-1-k] = temp;
                        }
                        return;
                    }
                }
            }  
        }
        for(int i = 0; i < len/2; i++){
            int temp = nums[i];
            nums[i] = nums[len-1-i];
            nums[len-1-i] = temp;
        }
        return;
    }
}


其他解法类似,只是将反转和交换的过程分开了,反转的过程可以借鉴下,采用两个指针往中间靠近,不容易出错,自己计算次数老出错。


46. Permutations

题目:得到输入数组的所有排列序列。

思路:回溯(递归)——注意要判断list中是否已经包含该数,前提是输入数组每个元素均不相同。注意list也有contains方法。

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ret = new LinkedList<>();
        List<Integer> list = new LinkedList<>();
        backtrack(ret, nums, list, 0);
        return ret;
        
    }
    public void backtrack(List<List<Integer>> ret, int[] nums, List<Integer> list, int x){
        if(x == nums.length){
            ret.add(new LinkedList<Integer>(list));
            return;
        }
        else if(x > nums.length){
            return;
        }
        else{
            for(int i = 0; i < nums.length; i++){
                if(list.contains(nums[i])) continue;
                list.add(nums[i]);
                backtrack(ret, nums, list, x+1);
                list.remove(list.size()-1);
            }
        }
    }
}


改进的做法——在输入的nums做手脚,即打乱nums的顺序,每个交换相邻的位置,然后递归,最后复原。这样大大缩短了时间。

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ret = new LinkedList<>();
        backtrack(ret, nums, 0);
        return ret;
        
    }
    public void backtrack(List<List<Integer>> ret, int[] nums, int x){
        if(x == nums.length){
            List<Integer> list = new LinkedList<>();
            for(int n : nums){
                list.add(n);
            }
            ret.add(list);
            return;
        }
        else if(x > nums.length){
            return;
        }
        else{
            for(int i = x; i < nums.length; i++){
                int temp = nums[i];
                nums[i] = nums[x];
                nums[x] = temp;
                backtrack(ret, nums, x+1);
                nums[x] = nums[i];
                nums[i] = temp;
            }
        }
    }
}


47. Permutations II

题目:数组有重复数时

思路:在40题基础上增加去重的部分,设置flag判断是否跳过重复部分。判断被交换节点和交换节点之间是否有与交换节点相同值的节点,有就跳过。

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> ret = new LinkedList<>();
        backtrack(ret, nums, 0);
        return ret;
    }
    public void backtrack(List<List<Integer>> ret, int[] nums, int x){
        if(x == nums.length){
            List<Integer> list = new LinkedList<>();
            for(int n : nums){
                list.add(n);
            }
            ret.add(list);
            return;
        }
        else if(x > nums.length){
            return;
        }
        else{
            for(int i = x; i < nums.length; i++){
                boolean flag = true;
                for(int j = x; j < i; j++){
                    if(nums[j] == nums[i]){
                        flag = false;
                        break;
                    }
                }
                if(flag == false) continue;
                int temp = nums[i];
                nums[i] = nums[x];
                nums[x] = temp;
                backtrack(ret, nums, x+1);
                nums[x] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

60. Permutation Sequence

题目:找到全排序列中第k位的序列

思路:从数学的角度来做,按模值分成若干组。新建一个List,每次从中取出一个数加到返回并移除。

public class Solution {
    public String getPermutation(int n, int k) {
        List<Integer> list = new LinkedList<>();
        for(int i = 1; i <= n; i++){
            list.add(i);
        }
        StringBuilder sb = new StringBuilder();
        k--;
        for(int i = n-1; i > 0; i--){
            int jx = jie(i);
            String x = list.get(k/jx).toString();
            sb.append(x);
            list.remove(k/jx);
            k = k%jx;
        }
        sb.append(list.get(0).toString());
        return sb.toString();
    }
    public int jie(int n){
        int ret = 1;
        for(int i = 1; i <= n; i++){
            ret *= i;
        }
        return ret;
    }
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值