zoukankan      html  css  js  c++  java
  • 【LeetCode】 61

    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
    
        public ListNode rotateRight(ListNode head, int k) {
            if(head == null) return null;
            // 计算链表的节点数
            int n = 0;
            for(ListNode p = head; p != null; p = p.next) n++;
            // 取余
            k %= n;
            // 快指针前进k步
            ListNode slow = head, fast = head;
            while(k -- > 0) fast = fast.next;
            while(fast.next!= null){
                fast = fast.next;
                slow = slow.next;
            }
            // 节点交换 画图查看
            fast.next = head;
            head = slow.next;
            slow.next = null;
            return head;
        }
    

    62. 不同路径

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

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

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

    例如,上图是一个7 x 3 的网格。有多少可能的路径?

    示例 1:

    输入: m = 3, n = 2
    输出: 3
    解释:
    从左上角开始,总共有 3 条路径可以到达右下角。
    1. 向右 -> 向右 -> 向下
    2. 向右 -> 向下 -> 向右
    3. 向下 -> 向右 -> 向右
    

    示例 2:

    输入: m = 7, n = 3
    输出: 28
    

    提示:

    • 1 <= m, n <= 100
    • 题目数据保证答案小于等于 2 * 10 ^ 9

    动态规划【未优化】

        public int uniquePaths(int m, int n) {
            //f[m,n]表示走到m,n的路径 res = f[m-1][n-1]
            int[][] f = new int[m][n];
    
            for(int i = 0; i < m; i ++){
                for(int j = 0; j < n; j++){
                    // 第一行 和 第一列 只能从同一个方向过来
                    if(i == 0 || j == 0) f[i][j] = 1;
                    // 其他的位置 都有两个方向的来源
                    else f[i][j] = f[i - 1][j] + f[i][j - 1];
                }
            }
            return f[m - 1][n - 1];
        }
    

    空间优化

        public int uniquePaths(int m, int n) {
            int[] f = new int[n];
            Arrays.fill(f, 1);
            for(int i = 1; i < m; i ++){
                for(int j = 1; j < n; j ++){
                    f[j] += f[j - 1]; 
                }
            }
            return f[n - 1];
        }
    

    63. 不同路径 II

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

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

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

    网格中的障碍物和空位置分别用 10 来表示。

    示例 1:

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

    示例 2:

    输入:obstacleGrid = [[0,1],[0,0]]
    输出:1
    

    提示:

    • m == obstacleGrid.length
    • n == obstacleGrid[i].length
    • 1 <= m, n <= 100
    • obstacleGrid[i][j]01

    动态规划

    第一行第一列的情况: 一旦遇到障碍物, 后续的位置便都是0。

    其他情况:从上或左方向来,障碍物的位置f = 0。

    class Solution {
        public int uniquePathsWithObstacles(int[][] g) {
            int n = g.length, m = g[0].length;
            //f[m,n]表示走到m,n的路径 res = f[m-1][n-1]
            int[][] f = new int[n][m];
            // 初始化第一列
            for(int i = 0; i < n && g[i][0] == 0; i ++) f[i][0] = 1;
            // 初始化第一行
            for(int i = 0; i < m && g[0][i] == 0; i ++) f[0][i] = 1;
    		// 其他位置
            for(int i = 1; i < n; i ++){
                for(int j = 1; j < m; j ++){
                    if(g[i][j] == 1) continue;
                    f[i][j] = f[i - 1][j] + f[i][j - 1];
                }
            }
    
            return f[n - 1][m - 1];
        }
    }
    

    空间优化

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

    64. 最小路径和

    难度中等793收藏分享切换为英文接收动态反馈

    给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

    说明:每次只能向下或者向右移动一步。

    示例 1:

    输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
    输出:7
    解释:因为路径 1→3→1→1→1 的总和最小。
    

    示例 2:

    输入:grid = [[1,2,3],[4,5,6]]
    输出:12
    

    提示:

    • m == grid.length
    • n == grid[i].length
    • 1 <= m, n <= 200
    • 0 <= grid[i][j] <= 100

    动态规划

    class Solution {
        // 在grid 上原地操作
        public int minPathSum(int[][] grid) {
            int m = grid.length;
            int n = grid[0].length;
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (i == 0 && j == 0) {
                        continue;
                    // 第一行 只能从左边来
                    } else if (i == 0) {
                        grid[i][j] += grid[i][j - 1];
                    // 第一列 只能从上面来
                    } else if (j == 0) {
                        grid[i][j] += grid[i - 1][j];
                    // 取相对小的一个
                    } else {
                        grid[i][j] += Math.min(grid[i][j - 1],grid[i - 1][j]);
                    }
                }
            }
            return grid[m - 1][n - 1];
        }
    }
    

    65. 有效数字

    有效数字(按顺序)可以分成以下几个部分:

    1. 一个 小数 或者 整数
    2. (可选)一个 'e''E' ,后面跟着一个 整数

    小数(按顺序)可以分成以下几个部分:

    1. (可选)一个符号字符('+''-'
    2. 下述格式之一:
      1. 至少一位数字,后面跟着一个点 '.'
      2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
      3. 一个点 '.' ,后面跟着至少一位数字

    整数(按顺序)可以分成以下几个部分:

    1. (可选)一个符号字符('+''-'
    2. 至少一位数字

    部分有效数字列举如下:

    • ["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]

    部分无效数字列举如下:

    • ["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]

    给你一个字符串 s ,如果 s 是一个 有效数字 ,请返回 true

    示例 1:

    输入:s = "0"
    输出:true
    

    示例 2:

    输入:s = "e"
    输出:false
    

    示例 3:

    输入:s = "."
    输出:false
    

    示例 4:

    输入:s = ".1"
    输出:true
    

    提示:

    • 1 <= s.length <= 20
    • s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,或者点 '.'
    class Solution {
        // https://leetcode.com/problems/valid-number/discuss/1066333/Java-Easy-Solution-(with-comments)
        public boolean isNumber(String s) {
            boolean sign = false;
            boolean digit = false;
            boolean e = false;
            boolean dots = false;
            for(int i = 0; i < s.length(); i ++){
                // ±号的情况,满足条件: 只能出现一次符号且该位置是第一位或者前面是e
                if(s.charAt(i) == '+' || s.charAt(i) == '-') {
                    if((i == 0 || s.charAt(i - 1) == 'e') && !sign){
                        sign = true;
                        continue;
                    }else return false;
                }
                // 数字的限制较少, 直接标记一下并跳过
                if(s.charAt(i) >= '0' && s.charAt(i) <= '9'){
                    digit = true;
                    continue;
                }
                // 不能遇到点 或者 e
                if(s.charAt(i) == '.'){
                    if(e || dots) return false;
                    dots = true;
                    continue;
                }
                // 如果是e,前面要出现过数字,且没有出现e
                if((s.charAt(i) == 'e' || s.charAt(i) == 'E') && digit && !e){
                    digit = false;
                    sign = false;
                    e = true;
                    continue;
                }else return false;
     
            }
            if(digit) return true;
            else return false;
        }
    }
    

    66. 加一

    给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

    最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

    你可以假设除了整数 0 之外,这个整数不会以零开头。

    示例 1:

    输入: [1,2,3]
    输出: [1,2,4]
    解释: 输入数组表示数字 123。
    

    示例 2:

    输入: [4,3,2,1]
    输出: [4,3,2,2]
    解释: 输入数组表示数字 4321。
    
        public int[] plusOne(int[] digits) {
            for(int i = digits.length - 1; i >= 0; i --){
                if(digits[i] != 9){
                    digits[i] ++;
                    return digits;
                }
                digits[i] = 0;
            }
            // 每个都是0  1000
            int[] res = new int[digits.length + 1];
            res[0] = 1;
            return res;
        }
    

    67. 二进制求和

    给你两个二进制字符串,返回它们的和(用二进制表示)。

    输入为 非空 字符串且只包含数字 10

    示例 1:

    输入: a = "11", b = "1"
    输出: "100"
    

    示例 2:

    输入: a = "1010", b = "1011"
    输出: "10101"
    

    提示:

    • 每个字符串仅由字符 '0''1' 组成。
    • 1 <= a.length, b.length <= 10^4
    • 字符串如果不是 "0" ,就都不含前导零。

    模拟进位

    class Solution {
        public String addBinary(String a, String b) {
            int c = 0; // 进位
            int i = a.length() - 1, j = b.length() - 1;
            StringBuilder ans = new StringBuilder();
            int aa = 0, bb = 0;
            while(i >= 0 || j >= 0){
                aa = i < 0 ? 0 : a.charAt(i --) - '0';
                bb = j < 0 ? 0 : b.charAt(j --) - '0';
                c += aa + bb;
                ans.append(c % 2);
                c >>= 1;
            }
            if(c > 0) ans.append(c);
            return ans.reverse().toString();
        }
    }
    

    68. 文本左右对齐

    给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。

    你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。

    要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。

    文本的最后一行应为左对齐,且单词之间不插入额外的空格。

    说明:

    • 单词是指由非空格字符组成的字符序列。
    • 每个单词的长度大于 0,小于等于 maxWidth
    • 输入单词数组 words 至少包含一个单词。

    示例:

    输入:
    words = ["What","must","be","acknowledgment","shall","be"]
    maxWidth = 16
    输出:
    [
      "What   must   be",
      "acknowledgment  ",
      "shall be        "
    ]
    解释: 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
         因为最后一行应为左对齐,而不是左右两端对齐。       
         第二行同样为左对齐,这是因为这行只包含一个单词。
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/text-justification
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    

    https://www.youtube.com/watch?v=GqXlEbFVTXY

    class Solution {
        public List<String> fullJustify(String[] words, int maxWidth) {
            List<String> res = new ArrayList<>();
            int i = 0, n = words.length;
            // 双指针,划定每一行的单词范围
            while(i < n){
                int j = i + 1;
                int lineLength = words[i].length();
                while(j < n && 
                      (lineLength + words[j].length() + (j - i - 1) < maxWidth)){
                    lineLength += words[j].length();
                    ++ j;
                }
                int diff = maxWidth - lineLength;
                // 单词数量
                int numberOfWords = j - i;
                if(numberOfWords == 1 || j >= n) res.add(leftJustify(words, diff, i, j));
                else res.add(middleJustify(words, diff, i, j));
    
                i = j;
            }
            return res;
        }
    	// 一行的单词数量只有一个 或者最后一行 左对齐
        String leftJustify(String[] words, int diff, int i, int j){
            int spaceOnRight = diff - (j - i - 1);// 右边需要补充的空格数
            StringBuilder res = new StringBuilder(words[i]);
            for(int k = i + 1; k < j; k ++){
                res.append(" " + words[k]);
            }
            res.append(" ".repeat(spaceOnRight));
            return res.toString();
        }
    	// 左右两端对齐
        String middleJustify(String[] words, int diff, int i, int j){
            int spacesNeeded = j - i - 1;
            int spaces = diff / spacesNeeded;
            int extraSpaces = diff % spacesNeeded;
    
            StringBuilder res = new StringBuilder(words[i]);
            for(int k = i + 1; k < j; k ++){
                int spacesToApply = spaces + (extraSpaces-- > 0 ? 1 : 0);
                res.append(" ".repeat(spacesToApply) + words[k]);
            }
            return res.toString();
        }
    }
    

    69. x 的平方根

    实现 int sqrt(int x) 函数。

    计算并返回 x 的平方根,其中 x 是非负整数。

    由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

    示例 1:

    输入: 4
    输出: 2
    

    示例 2:

    输入: 8
    输出: 2
    说明: 8 的平方根是 2.82842..., 
         由于返回类型是整数,小数部分将被舍去。
    

    二分查找

    class Solution {
        public int mySqrt(int x) {
            if(x == 1) return 1;
            int l = 0, r = x / 2;
            while( l < r ){
                int mid = l + r + 1 >> 1;
                if (mid <= x / mid) l = mid;
                else r = mid - 1;
            }
            return r;
        }
    }
    

    70. 爬楼梯

    假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

    每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

    注意:给定 n 是一个正整数。

    示例 1:

    输入: 2
    输出: 2
    解释: 有两种方法可以爬到楼顶。
    1.  1 阶 + 1 阶
    2.  2 阶
    

    示例 2:

    输入: 3
    输出: 3
    解释: 有三种方法可以爬到楼顶。
    1.  1 阶 + 1 阶 + 1 阶
    2.  1 阶 + 2 阶
    3.  2 阶 + 1 阶
    

    动态规划

        public int climbStairs(int n) {
            if (n <= 2) {
                return n;
            }
    
            int[] f = new int[n + 1];
            f[1] = 1;
            f[2] = 2;
            for (int i = 3; i <= n; i++) {
                f[i] = f[i - 1] + f[i - 2];
            }
            return f[n];
        }
    

    动态优化 空间优化

    class Solution {
        public int climbStairs(int n) {
            int a = 0, b = 0, c = 1;
            for (int i = 1; i <= n; ++i) {
                a = b; 
                b = c; 
                c = a + b;
            }
            return c;
        }
    }
    

    时间复杂度 O(N)

    数学解法

    [f(n) = f(n - 1) + f(n - 2)$$的特征方程: ]

    x^2 = x + 1

    [求得$$ x_1 = {1 + sqrt{5} over 2}, x_2 = {1 - sqrt{5} over 2}$$, 设通解$$f(n) = c_1 x_1^n + c_2x_2^n$$,代入初始条件$$f(1) = 1, f(2) = 1$$, 得$c_1 = {1 over sqrt5}, c_2 = -{1 over sqrt5}$,得到递推数列的通项公式 : ]

    Fn = {1 over sqrt{5}} left[ left( {1 + sqrt{5} over 2} ight)^2- left( {1 - sqrt{5} over 2} ight)^2 ight]

    [ ```java public int climbStairs(int n) { double sqrt5 = Math.sqrt(5); double fibn = Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1); return (int) Math.round(fibn / sqrt5); } ```]

  • 相关阅读:
    基于UML和ASP.NET实现三层B/S结构系统开发
    通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行(转)
    GOOGLE浏览器(已经可以下载啦)
    虽然很老,但是还是挺有用,而且经常要看。META
    ASP.NET保持用户状态的九种选择
    设计ASP.NET应用程序的七大绝招
    将更智能的 ASP.NET 文件下载体验内置到您的 Web 应用程序中 (MSDN)
    据说是民间最准确的算命法则
    ASP.NET是否是微软继MFC之后最无用的框架?
    宁波单身公寓出租
  • 原文地址:https://www.cnblogs.com/summerday152/p/14449093.html
Copyright © 2011-2022 走看看