Java实现LeetCode 题号:61 - 70

228 阅读7分钟

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

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

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
         if(head==null||k==0){
        return head;
    }
    ListNode cursor=head;
    ListNode tail=null;//尾指针
    int length=1;
    while(cursor.next!=null)//循环 得到总长度
    {
        cursor=cursor.next;
        length++;
    }
    int loop=length-(k%length);//得到循环的次数
    tail=cursor;//指向尾结点
    cursor.next=head;//改成循环链表
    cursor=head;//指向头结点
    for(int i=0;i<loop;i++){//开始循环
        cursor=cursor.next;
        tail=tail.next;
    }
    tail.next=null;//改成单链表
    return cursor;//返回当前头
    }
}

62. 不同路径

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

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

问总共有多少条不同的路径? 在这里插入图片描述

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

说明:m 和 n 的值均不超过 100。

示例 1:

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

  1. 向右 -> 向右 -> 向下
  2. 向右 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向右 示例 2:

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

class Solution {
     public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                //如果是第一行或者第一列来到这个位置的方法为1
                if (i == 0 || j == 0)
                    dp[i][j] = 1;
                else {
                //每一步只能是当前位置的上一行或者上一列来到此位置,
                //把那两个的方法数加起来就是到达当前位置的方法数
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];        
    }
}

63. 不同路径 II

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

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

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

在这里插入图片描述

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

说明:m 和 n 的值均不超过 100。

示例 1:

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

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/un… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
     public int uniquePathsWithObstacles(int[][] arr) {
        if (arr == null || arr.length <= 0) {
            return 0;
        }
        int rows = arr.length;
        int cols = arr[0].length;
        int[][] dp = new int[rows][cols];

        for (int i = 0; i < cols; i++) 
            if (arr[0][i] == 1) {
               dp[0][i] = 0;
               break;   // 遇到障碍后面的都无法到达直接返回就行 默认就是0
            }      
            else dp[0][i] = 1;
    
        for (int i = 0; i < rows; i++) 
            if (arr[i][0] == 1) {
                 dp[i][0] = 0;    
                 break;  // 遇到障碍后面的都无法到达直接返回就行 默认就是0
            }  
            else dp[i][0] = 1;                 
            
        for (int i = 1; i < rows; i++) {
            for (int j = 1; j < cols; j++) {
                if (arr[i][j] == 1)  dp[i][j] = 0; // 遇到障碍就是0
                else dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; // dpdpdp
            }
        }    
        return dp[rows - 1][cols - 1];
    }
}

64. 最小路径和

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

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

示例:

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

和上面的题基本类似,不过是这次带了路径值
初始话的时候第一行和第一列的值为grid中相应的值

class Solution {
     public int minPathSum(int[][] grid) {
        if (grid == null || grid.length < 1 || grid[0] == null || grid[0].length < 1) {
            return 0;
        }
        
        int row = grid.length;
        int col = grid[row - 1].length;
        
        int dp[][] = new int[row][col];
        
        dp[0][0] = grid[0][0];
        
        for (int i = 1;i < row;i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        
        for (int i = 1;i < col;i++) {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        
        for (int i = 1;i < row;i++) {
            for (int j = 1;j < col;j++) {
                //还是通过当前位置的上一行或者上一列来的,取两种方法中最小的路径值
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        
        return dp[row - 1][col - 1];
    }
}

65. 有效数字

验证给定的字符串是否可以解释为十进制数字。

例如:

"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3   " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false

说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:

数字 0-9 指数 - "e" 正/负号 - "+"/"-" 小数点 - "." 当然,在输入中,这些字符的上下文也很重要。

更新于 2015-02-10: C++函数的形式已经更新了。如果你仍然看见你的函数接收 const char * 类型的参数,请点击重载按钮重置你的代码。

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/va… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    char[] chars;
    boolean point = false;//是否有小数部分
    boolean exponent = false;//是否有指数部分
    public boolean isNumber(String s) {
        s = s.trim();//去空格
        int length = s.length();
        if(length == 0){
            return false;
        }
        chars = s.toCharArray();//转字符数组
        String[] ss = s.split("e");//以e分隔数组为两部分
        if(ss.length == 0){//只有e 错误
            return false;
        }
        if(ss[0].length() == 0) return false;//如果e之前的部分为空 错误
        if(ss[0].length() < length) exponent = true;//如果前面部分字符长小于字符串长度,说明有指数部分
        if(ss[0].length() == length -1){
            return false;
        }
        String[] pre = ss[0].split("\\.");//以小数点分隔
        
        if(pre.length == 0){//如果只有小数点 错误
            return false;
        }
        if(pre[0].length() < ss[0].length()) point = true;
        //如果分隔后前面部分小于原来的长度,说明有小数部分      

        boolean result = pre(0, pre[0].length());
        //整数部分是否正确
        result = result && middle(pre[0].length()+1, ss[0].length());
        //中间部分是否正确
        if(exponent){//如果有指数部分
            result = result && is(ss[0].length() +1, length);
            //指数部分是否正确
        }
        return result;
    }
    public boolean pre(int i, int length){//判断整数部分是否正确
        if(i >= length){
            //如果整数部分为空 由于.1也是正确的,所以先返回正确
            return true;
        }
        //第一个字符是加减号,i+1
        if(chars[i] == '+' || chars[i] == '-') {
            i++;
        }
        if(i == length && !point){
            //如果没有小数部分,但是只有正负,返回错误
            return false;
        }
        for(; i < length; i++){
            //遍历整数部分
            if(chars[i] < '0' || chars[i] > '9'){
                //不是0-9就返回错误
                return false;
            }
            
        }
        //到这,整数部分就是正确的了
        return true;
    }
    public boolean middle(int i, int length){//小数部分
        if(i >= length && point ){
            //如果有小数点,但是小数部分为空 
            if(chars[i - 2] >= '0' && chars[i - 2] <= '9') {
                //如果小数点之前有数字返回正确
                return true;
            }
            //没有返回错误
            return false;
        }
        for(; i < length; i++){//遍历中间部分
            if(chars[i] < '0' || chars[i] > '9'){
                //不是0-9就返回错误
                return false;
            }
            
        }
        return true;
    }
    public boolean is(int i, int length){//指数部分
        if(i == 1){
            //在进来之前已经判断有指数部分,如果e前面为空,返回错误
            return false;
        }  
        //指数部分也可能有正负
        if(chars[i] == '+' || chars[i] == '-') {
            i++;
        }
        //之后正负号,返回错误
        if( i == length){
            return false;
        }
        for(; i < length; i++){
            //遍历指数部分
            if(chars[i] < '0' || chars[i] > '9'){
                //不是0-9返回错误
                return false;
            }
            
        }
        return true;
    }
}

66. 加一

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

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

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

示例 1:

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

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

class Solution {
     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;
		}
                //跳出for循环,说明数字全部是9
		int[] temp = new int[digits.length + 1];
		temp[0] = 1;
		return temp;
    }
}

67. 二进制求和

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

输入为非空字符串且只包含数字 1 和 0。

示例 1:

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

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

class Solution {
    public String addBinary(String a, String b) {
        if(a == null || a.length() == 0) return b;
        if(b == null || b.length() == 0) return a;

        StringBuilder stb = new StringBuilder();
        int i = a.length() - 1;
        int j = b.length() - 1;
        
        int c = 0;  // 进位
        while(i >= 0 || j >= 0) {
            if(i >= 0) c += a.charAt(i --) - '0';
            if(j >= 0) c += b.charAt(j --) - '0';
            stb.append(c % 2);
            c >>= 1;
        }
        
        String res = stb.reverse().toString();
        return c > 0 ? '1' + res : res;
    }
}

68. 文本左右对齐

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

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

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

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

说明:

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

输入:
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
输出:
[
   "This    is    an",
   "example  of text",
   "justification.  "
]
示例 2:

输入:
words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16
输出:
[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]
解释: 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
     因为最后一行应为左对齐,而不是左右两端对齐。       
     第二行同样为左对齐,这是因为这行只包含一个单词。
示例 3:

输入:
words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
输出:
[
  "Science  is  what we",
  "understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]
class Solution {
      
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ret = new ArrayList<>();
        
        int index = 0;
        while(index < words.length){
            int cur = index, len = 0;
            // len + words[cur].length() + cur - index 为单词之间取 一个空格的长度
            while(cur < words.length && len + words[cur].length() + cur - index <= maxWidth){
                // 计算纯单词长度
                len = len + words[cur++].length();
            }
            cur--;
            // System.out.println(cur + " " + len);
            StringBuilder sb = new StringBuilder();
            // 区分最后一行
            if(cur == words.length - 1){
                for(int i = index; i <= cur; i++){
                    sb.append(words[i]);
                    if(i < cur){
                        sb.append(' ');
                    }
                }
            }else{
                int base = cur > index ? (maxWidth - len) / (cur - index) : (maxWidth - len);
                String baseStr = genSpace(base);
                int left = cur > index ? (maxWidth - len) % (cur - index) : 0;
                String leftStr = genSpace(base + 1);
                for(int i = index; i <= cur; i++){
                    sb.append(words[i]);
                    if(i < cur){
                        sb.append(left > 0 ? leftStr : baseStr);
                        left--;
                    }
                }
            }
            if(sb.length() < maxWidth){
                sb.append(genSpace(maxWidth - sb.length()));
            }
            ret.add(sb.toString());
            index = cur + 1;
        }
        return ret;
    }
    
    private String genSpace(int n){
        char[] cs = new char[n];
        Arrays.fill(cs, ' ');
        return new String(cs);
    }
}

69. x 的平方根

实现 int sqrt(int x) 函数。

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

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

示例 1:

输入: 4 输出: 2 示例 2:

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

0x5f3759df是平方根倒数速算法
class Solution {
     public int mySqrt(int x) {
        long t = x;
	t = 0x5f3759df - (t >> 1);
	while (!(t*t <= x && (t+1)*(t+1) > x))
		t = (x/t + t)/2;
	return (int)t;
    }
}

70. 爬楼梯

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

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

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

示例 1:

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

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
3.  1 阶 + 1 阶 + 1 阶
4.  1 阶 + 2 阶
5.  2 阶 + 1 阶
class Solution {
//有点类似斐波那契数列
     public int climbStairs(int n) {
        if (n <= 1)
            return 1;
        else if (n == 2)
            return 2;
        else {
            int res = 0;
            int i = 1, j = 2;
            int k = 3;
            while (k <= n) {
                //当前的方法来自与前两节楼梯方法的和
                //前一节楼梯,在走一步就是当前步数
                //前两节楼梯,再走两节就是当前步数
                res = i + j;
                i = j;
                j = res;
                k++;
            }
            return res;
        }        
    }
}