Page 28 of 61

LeetCode刷题【剑指 Offer 05】替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

 

示例 1:

输入:s = "We are happy."
输出:"We%20are%20happy."

 

限制:

0 <= s 的长度 <= 10000

Related Topics
  • 字符串

  • 👍 229
  • 👎 0
  • 【一个变仨】有多少个空格就长度多多少个2呗

    不复杂,看代码遍历下看下有几个空格,一个空格变成`%20`的三个这样长度就多出来了2。然后把原来字符串s对应复制到新的char[]数组中,如果遇到了空格,就赋值为’%’和’2’和’0′,并且下标往后移动两位

    class Solution {
        public String replaceSpace(String s) {
            int count = 0;
            for (int i = 0; i < s.length(); i++) {
                count += s.charAt(i) == ' '?1:0;
            }
            if (count == 0){
                return s;
            }
            char[] arr = new char[s.length()+ count*2 ];
            int idxForS = -1;
            int idxForArr = 0;
            while (++idxForS < s.length()){
                if (s.charAt(idxForS) != ' '){
                    arr[idxForArr] = s.charAt(idxForS);
                }else{
                    arr[idxForArr] = '%';
                    arr[++idxForArr] = '2';
                    arr[++idxForArr] = '0';
                }
                idxForArr++;
            }
            return new String(arr);
        }
    }

    LeetCode刷题【64】最小路径和

    给定一个包含非负整数的 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
    Related Topics
  • 数组
  • 动态规划
  • 矩阵

  • 👍 1029
  • 👎 0
  • 太简单了,边界情况额外处理下,剩下就是中间的咵咵咵的

    class Solution {
        public int minPathSum(int[][] grid) {
            for (int i = 1; i < grid.length || i < grid[0].length; i++) {
                if (i < grid.length){
                    grid[i][0] += grid[i-1][0];
                }
                if (i < grid[0].length){
                    grid[0][i] += grid[0][i-1];
                }
            }
    
            for (int row = 1; row < grid.length; row++) {
                for (int col = 1; col < grid[row].length; col++) {
                    grid[row][col] = Math.min( grid[row-1][col],grid[row][col-1]) + grid[row][col];
                }
            }
            return grid[grid.length-1][grid[0].length-1];
        }
    }

    LeetCode刷题【38】外观数列

    给定一个正整数 n ,输出外观数列的第 n 项。

    「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

    你可以将其视作是由递归公式定义的数字字符串序列:

    • countAndSay(1) = "1"
    • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

    前五项如下:

    1.     1
    2.     11
    3.     21
    4.     1211
    5.     111221
    第一项是数字 1 
    描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
    描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
    描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
    描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
    

    描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

    例如,数字字符串 "3322251" 的描述如下图:

     

    示例 1:

    输入:n = 1
    输出:"1"
    解释:这是一个基本样例。
    

    示例 2:

    输入:n = 4
    输出:"1211"
    解释:
    countAndSay(1) = "1"
    countAndSay(2) = 读 "1" = 一 个 1 = "11"
    countAndSay(3) = 读 "11" = 二 个 1 = "21"
    countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"
    

     

    提示:

    • 1 <= n <= 30
    Related Topics
  • 字符串

  • 👍 765
  • 👎 0
  • 字符串模拟,这种阅读起来好像还是比直接sb拼接费劲不少。岂止费劲,还看得眼花。
    逻辑也是一样的,

    • 从’1’开始
    • 2个’1′ 就是 “21”
    • 然后“21”就是 1个’2’、1个’1’即“1211”
    • “1211”就是1个’1’、1个’2’、2个’1’,即“111221”
    • 后面依次类推

    class Solution {
        public String countAndSay(int n) {
            if (n == 1){
                return "1";
            }
            char[][] arr = new char[2][4500];
            arr[0][0] = '1';
            int i = 2;
            int cur = 1;
            int pre = 0;
            int preIdx = 0;
            int curIdx = 0;
            while (i <= n){
                cur = (i-1) % 2;
                pre = i % 2;
                preIdx = 0;
                curIdx = -1;
                while (arr[pre][preIdx] != '\u0000'){
                    char numChar = arr[pre][preIdx];
                    int count = 1;
                    while (arr[pre][preIdx] == arr[pre][preIdx+1]){
                        count++;
                        preIdx++;
                    }
                    preIdx++;
                    if (count > 10){
                        int countStringSize = 1;
                        int x = 10;
                        while (count/x != 0){
                            x *= 10;
                            countStringSize++;
                        }
                        curIdx++;
                        while (--countStringSize>=0){
                            arr[cur][curIdx + countStringSize] = (char)('0'+ count%10);
                            count = count / 10;
                        }
                        curIdx += countStringSize-1;
                    }else{
                        arr[cur][++curIdx] = (char)('0' + count);
                    }
                    arr[cur][++curIdx] = numChar;
                }
                i++;
            }
            char[] strChars = new char[curIdx+1];
            System.arraycopy(arr[cur],0,strChars,0,curIdx+1);
            return new String(strChars);
        }
    }

    LeetCode刷题【剑指 Offer II 069】山峰数组的顶部

    符合下列属性的数组 arr 称为 山峰数组山脉数组)

    • arr.length >= 3
    • 存在 i0 < i < arr.length - 1)使得:
      • arr[0] < arr[1] < ... arr[i-1] < arr[i]
      • arr[i] > arr[i+1] > ... > arr[arr.length - 1]

    给定由整数组成的山峰数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i ,即山峰顶部。

     

    示例 1:

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

    示例 2:

    输入:arr = [1,3,5,4,2]
    输出:2
    

    示例 3:

    输入:arr = [0,10,5,2]
    输出:1
    

    示例 4:

    输入:arr = [3,4,5,1]
    输出:2
    

    示例 5:

    输入:arr = [24,69,100,99,79,78,67,36,26,19]
    输出:2
    

     

    提示:

    • 3 <= arr.length <= 104
    • 0 <= arr[i] <= 106
    • 题目数据保证 arr 是一个山脉数组

     

    进阶:很容易想到时间复杂度 O(n) 的解决方案,你可以设计一个 O(log(n)) 的解决方案吗?

     

    注意:本题与主站 852 题相同:https://leetcode-cn.com/problems/peak-index-in-a-mountain-array/

    Related Topics
  • 数组
  • 二分查找

  • 👍 15
  • 👎 0
  • 一般选手

    嗯,找峰值。
    先排除几个特殊情况

    • 数组长度只有1,直接返回0
    • 数组长度只有2,要么0下标的大要么1下标的大
    • 整个数组都是递增的,或者整个数组都是递减的,判断前两位或者后两位的大小关系,这个情况可以包含前面的情况2
    • 剩下的就是在数组中间一定有峰值的,且数组长度一定是大于2的情况,用二分法尝试寻找
      • 找到二分中间值,如果这个比左边和右边 都大,直接返回下标
      • 如果中间值和前面后面组成是递增的,则在说明峰值在后面,继续在后面的区间寻找
      • 如果中间值和前面后面组成的是递减的,则说明峰值在前面,则继续在前面的区间寻找
      • 因为给定的数组肯定只有一个峰值,所以除了上面的三种情况之外没有其他的情况了

    有兴趣的话可以看下另外一题162. 寻找峰值,很像,但是又有点不一样,这题给的数组中可能存在多个峰值。不过只要求返回一个峰值,本质上讨论的情况还是基本一样的。

    关于二分的模板和边界情况的需要多加注意

    class Solution {
        public int peakIndexInMountainArray(int[] arr) {
            if (arr.length == 1){
                return 0;
            }
            if (arr[0] > arr[1]){
                return 0;
            }
            if (arr[arr.length-1] > arr[arr.length-2]){
                return arr.length;
            }
            int left = 0;
            int right = arr.length - 1;
            while (left < right){
                int mid = left + ( (right - left) >> 1 );
                if (arr[mid - 1] < arr[mid] &&  arr[mid + 1] < arr[mid]){
                    return mid;
                }
                if (arr[mid - 1] < arr[mid] &&  arr[mid + 1] > arr[mid]){
                    //上升
                    left = mid+1;
                }else{
                    //下降
                    right = mid;
                }
            }
            return left;
        }
    }
    

    不一般选手

    题面中提供了以下信息

     3 <= arr.length <= 10⁴ 
     0 <= arr[i] <= 10⁶ 
     题目数据保证 arr 是一个山脉数组 

    嗯,才这么点数据,看了下 34 个测试用例,这不简单么?直接撸一下

    class Solution {
        public int peakIndexInMountainArray(int[] arr) {
            int i = -1;
            for (; ++i < arr.length && arr[i] < arr[i+1];);
            return i;
        }
    }

    LeetCode刷题【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
    Related Topics
  • 数组
  • 动态规划
  • 矩阵

  • 👍 642
  • 👎 0
  • 同上一题LeetCode刷题【62】不同路径

    之前没石头,那么如果加了石头之后呢,我们用0表示,说明到达这个格子的方法有0种

    那么路径就变成了这样

    class Solution {
        public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    
            if (obstacleGrid[0][0] == 1){
                return 0;
            }
    
            int rowCount = obstacleGrid.length;
            int colCount = obstacleGrid[0].length;
            int[][] dp = new int[rowCount][colCount];
            for (int row = 0; row < rowCount; row++) {
                for (int col = 0; col < colCount; col++) {
                    if (col==0 && row == 0){
                        dp[row][col] = 1;
                        continue;
                    }
                    int left = col > 0 ? dp[row][col-1] : 0;
                    int up = row > 0 ? dp[row-1][col] : 0;
                    dp[row][col] = obstacleGrid[row][col] == 1 ? 0 : ( left + up );
                }
            }
            return dp[rowCount-1][colCount-1];
        }
    }

    LeetCode刷题【62】不同路径

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

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

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

     

    示例 1:

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

    示例 2:

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

    示例 3:

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

    示例 4:

    输入:m = 3, n = 3
    输出:6

     

    提示:

    • 1 <= m, n <= 100
    • 题目数据保证答案小于等于 2 * 109
    Related Topics
  • 数学
  • 动态规划
  • 组合数学

  • 👍 1141
  • 👎 0
  • 机器人行走路径只能向右或者向下。那么每个到达每个格子的上一步可能是左边往右过来的,或者是上面一个格子下来的

    边界情况,横向第0行或者纵向第一列只有一种可能性。你可以选择单独初始化或者外面部分的值取0。

    class Solution {
        public int uniquePaths(int m, int n) {
            int[][] dp = new int[m][n];
            Arrays.fill(dp[0],1);
            for (int row = 1; row < m; row++) {
                dp[row][0] = 1;
                for (int col = 1; col < n; col++) {
                    dp[row][col] = dp[row][col-1] + dp[row-1][col];
                }
            }
            return dp[m-1][n-1];
        }
    }
    

    当然,如果你把这个图右旋45°的话,你会看到这样一幅图

    是不是非常眼熟?对他就是LeetCode刷题【118】杨辉三角LeetCode刷题【119】杨辉三角 II