LeetCode刷题记录9.29

第46题 全排列(重点)

给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

java解法:

public class Permutations46 {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result= new ArrayList<>();
        ArrayList<Integer> list = new ArrayList<>();
        for(int i:nums){
            list.add(i);
        }
        int first = 0;
        backtrap(list,first,result);
        return result;
    }
    public void backtrap(ArrayList<Integer> list,int first, List<List<Integer>> result){
        if(first==list.size()){
            result.add(new ArrayList(list));
        }
        for(int i = first;i<list.size();i++){
            Collections.swap(list,first,i);
            backtrap(list,first+1,result);
            Collections.swap(list,first,i);
        }
    }
}

这道题是比较典型的关于回溯的题。在这道题中,我们以first来进行深度扩展。使用数字之间的交换来实现效果。以i来进行横向扩展。这种题型一点要背下来。

第60题 第k个排列(重)

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。

说明:

给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
示例 1:

输入: n = 3, k = 3
输出: "213"

示例 2:

输入: n = 4, k = 9
输出: "2314"

java代码:

import java.util.ArrayList;
import java.util.List;

public class Solution {

    public String getPermutation(int n, int k) {
        int[] nums = new int[n];
        boolean[] used = new boolean[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i + 1;
            used[i] = false;
        }
        List<String> pre = new ArrayList<>();
        return dfs(nums, used, n, k, 0, pre);
    }

    private int factorial(int n) {
        // 这种编码方式包括了 0 的阶乘是 1 这种情况
        int res = 1;
        while (n > 0) {
            res *= n;
            n -= 1;
        }
        return res;
    }

    private String dfs(int[] nums, boolean[] used, int n, int k, int depth, List<String> pre) {
        if (depth == n) {
            StringBuilder sb = new StringBuilder();
            for (String c : pre) {
                sb.append(c);
            }
            return sb.toString();
        }
        int ps = factorial(n - 1 - depth);
        for (int i = 0; i < n; i++) {
            if (used[i]) {
                continue;
            }
            if (ps < k) {
                k -= ps;
                continue;
            }
            pre.add(nums[i] + "");
            used[i] = true;
            return dfs(nums, used, n, k, depth + 1, pre);
        }
        // 如果参数正确的话,代码不会走到这里
        throw new RuntimeException("参数错误");
    }
}

这道题是利用了回溯和剪枝的方法。因为我们每次要找第k个节点。那么我们每次用回溯算法访问一个节点的时候。若那个 节点不是叶子节点。那么这个节点上能产生多少个组合是可以算出来的。如果算出来的结果小于k值那么这个节点就可以不用往下访问了。从而转移到另外的节点上面去。这道题有点难。

第61题 旋转列表

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1: 5->1->2->3->4->NULL
向右旋转 2: 4->5->1->2->3->NULL

示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1: 2->0->1->NULL
向右旋转 2: 1->2->0->NULL
向右旋转 3: 0->1->2->NULL
向右旋转 4: 2->0->1->NULL

java代码:

public class Rotate_List61 {
    public ListNode rotateRight(ListNode head, int k) {
        if(head==null) return head;
        ListNode p1 = head;
        ListNode p2 = head;
        int length=0;
        while(p1!=null){
            length++;
            p1=p1.next;
        }
        p1 = head;
        k = k%length;
        for(int i=0;i<k;i++){
            p2= p2.next;
            if(p2==null) p2=head;
        }

        if(p1==p2) return head;

        while(p2.next!=null){
            p1 = p1.next;
            p2 = p2.next;
        }
        ListNode result = p1.next;

        p2.next = head;

        p1.next = null;
        return result;

    }
}

这道题比较简单,但是要注意一开始要先确定链表的length。不然直接用k来循环的话时间复杂度就是O(max(n,k))。而且在题内的时间消耗很大。

第62题 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

java代码:

class Solution {
    public int uniquePaths(int m, int n) {
                int[][] f = new int[m+1][n+1];
        for(int i=0;i<=m;i++){
            f[m][0] = 0;
        }
        for(int i = 0;i<=n;i++){
            f[0][n] = 0;
        }
        for(int i = 1;i<=m;i++){
            for(int j = 1;j<=n;j++){
                if(i==j&&j==1){
                    f[i][j] = 1;
                    continue;
                }
                f[i][j] = f[i-1][j]+f[i][j-1];
            }
        }
        return f[m][n];
    }
}

简单的动态规划超过了100的人

第63题 不同路径2

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
示例 1:

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

java代码:

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
                int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][] f = new int[m+1][n+1];
        for(int i=0;i<=m;i++){
            f[m][0] = 0;
        }
        for(int i = 0;i<=n;i++){
            f[0][n] = 0;
        }
        for(int i = 1;i<=m;i++){
            for(int j = 1;j<=n;j++){
                    if(obstacleGrid[m-i][n-j]==1){
                    f[i][j]=0;
                    continue;
                }
                if(i==j&&j==1){
                    f[i][j] = 1;
                    continue;
                }
            
                f[i][j] = f[i-1][j]+f[i][j-1];
            }
        }
        return f[m][n];
    }
}

和上一题基本一样。加了个判断和坐标映射而已。坐标映射是将f的坐标转换到障碍的坐标当中。

第64题最小路径和

用动态规划很简单。不说了

第69题 x的平方根

很简单注意进制的变化:

class Solution {
    public int mySqrt(int x) {
       if(x==0)return x;
        float low = 1; float high = x;
        while((int)low<(int)high){
            double midle = ((double)low+(double)high)/2;
            if(midle*midle==x){
                return (int)midle;
            }
            else if(midle*midle>x)
                high = (float) midle;
            else
                low = (float)midle;

        }
        

        if((int)low * (int)low > x){
            return (int)(low)-1;}
        else if((low+1)*(low+1)<(float)x)
            return (int)(low+1);
        else return (int)low;
    }
}

使用了二分法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值