编程练习题(3)

最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

Java版本:

public static int maxSubArray(int[] nums) {
    
    
       int pre = 0, res = nums[0];
       for (int val : nums){
    
    
           pre = Math.max(val, val + pre);
           res = Math.max(res, pre);
       }
        return res;
    }

Python版本:

# 最大子序和
# 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

class Solution:
    def maxSubArray(self, nums: list) -> int:
        pre, res = 0, nums[0]
        for i in range(0,len(nums)):
            pre = max(nums[i], pre + nums[i])
            res = max(res, pre)
        return res

# 测试
s = Solution()
nums =  [-2,1,-3,4,-1,2,1,-5,4]
print(s.maxSubArray(nums))
答案:
6

跳跃游戏

给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。

Java版本:

/*
    依次遍历数组中的每一个位置,并实时维护 最远可以到达的位置
     */
    public static boolean canJump(int[] nums) {
    
    
        int max = 0;
        for (int i = 0 ; i < nums.length ; i++){
    
    
            max = Math.max(max, i + nums[i]);
            if (max >= nums.length - 1){
    
    
                return true;
            }
        }
        return false;
    }

Python版本:

# 跳跃游戏
class Solution:
    def canJump(self, nums: list) -> bool:
        n = len(nums)
        maxVal = 0
        for i in range(0, n):
            if i <= maxVal:
                maxVal = max(maxVal, i+nums[i])
                if maxVal >= n-1:
                    return True
        return False


# 测试
s = Solution()
nums = [2,3,1,1,4];
print(s.canJump(nums))

# 答案:
True

螺旋矩阵

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

Java版本:

/*旋转添加输出*/
    public static List<Integer> spiralOrder(int[][] matrix) {
    
    
        List<Integer> res = new ArrayList<>();
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0){
    
    
            return res;
        }
        int up = 0, down = matrix.length - 1;
        int left = 0, right = matrix[0].length - 1;
        int count = matrix.length * matrix[0].length;
        while (count > 0){
    
    
            for (int i = left ; count > 0 && i <= right; i++){
    
    
                res.add(matrix[up][i]);
                count--;
            }
            up++;
            for (int i = up ; count > 0 && i <= down; i++){
    
    
                res.add(matrix[i][right]);
                count--;
            }
            right--;
            for (int i = right; count > 0 && i >= left ; i--){
    
    
                res.add(matrix[down][i]);
                count--;
            }
            down--;
            for (int i = down; count > 0 && i >= up ; i--){
    
    
                res.add(matrix[i][left]);
                count--;
            }
            left++;
        }
        return res;
    }

Python版本:

# 螺旋矩阵
class Solution:
    def spiralOrder(self, matrix: list) -> list:
        if not matrix or not matrix[0]:
            return list()
        left, up = 0, 0
        down, right = len(matrix)-1, len(matrix[0])-1
        count = len(matrix) * len(matrix[0])
        res = list()
        while count > 0:
            for i in range(left, right+1):
                if count > 0:
                    res.append(matrix[up][i])
                    count -= 1
            up += 1

            for i in range(up, down+1):
                if count > 0:
                    res.append(matrix[i][right])
                    count -= 1
            right -= 1

            for i in range(right, left-1, -1):
                if count > 0:
                    res.append(matrix[down][i])
                    count -= 1
            down -= 1

            for i in range(down, up-1, -1):
                if count > 0:
                    res.append(matrix[i][left])
                    count -= 1
            left += 1

        return res


# 测试
s = Solution()
matrix = [
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
print(s.spiralOrder(matrix))

# 答案:
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]

合并区间

给出一个区间的集合,请合并所有重叠的区间。

Java解法:

 public static int[][] merge(int[][] intervals) {
    
    
        /*先将每个区间的左端点,从小到大排序*/
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        int n = intervals.length;
        int [][]res = new int[n][2];
        int idx = -1;
        for (int[] interval: intervals) {
    
    
            /*
             如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,
             则不合并,直接将当前区间加入结果数组。
             */
            if (idx == -1 || interval[0] > res[idx][1]) {
    
    
                res[++idx] = interval;
            } else {
    
    
                // 反之将当前区间合并至结果数组的最后区间
                res[idx][1] = Math.max(res[idx][1], interval[1]);
            }
        }
        return Arrays.copyOf(res, idx + 1);
    }

Python解法:

# 合并区间
class Solution:
    def merge(self, intervals: list) -> list:
        if not intervals: return []
        intervals.sort()
        res = [intervals[0]]
        for x, y in intervals[1:]:
            if res[-1][1] < x:
                res.append([x, y])
            else:
                res[-1][1] = max(y, res[-1][1])
        return res


# 测试
s = Solution()
intervals = [[1,3],[2,6],[8,10],[15,18]]
print(s.merge(intervals))

# 答案:
[[1, 6], [8, 10], [15, 18]]

插入区间

给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

Python版本:

# 插入区间
class Solution:
    def insert(self, intervals: list, newInterval: list) -> list:
        left, right = newInterval
        flag = False
        res = list()
        for le, ri in intervals:
            if le > right:
                # 在插入区间的右侧且无交集
                if not flag:
                    res.append([left, right])
                    flag = True
                res.append([le, ri])
            elif ri < left:
                # 在插入区间的左侧且无交集
                res.append([le, ri])
            else:
                # 与插入区间有交集,计算它们的并集
                left = min(left, le)
                right = max(right, ri)

        if not flag:
            res.append([left, right])
        return res



# 测试
s = Solution()
intervals = [[1,3],[4,5],[7,9]]
newInterval = [2,5]
print(s.insert(intervals,newInterval))

# 答案:
[[1, 5], [7, 9]]

Java版本:

public static int[][] insert(int[][] intervals, int[] newInterval) {
    
    
        if (newInterval == null){
    
    
            return intervals;
        }
        ArrayList<int[]> res = new ArrayList<>();
        ArrayList<int[]> cur = new ArrayList<>();
        for (int []row : intervals){
    
    
            cur.add(row);
        }
        int i = 0;
        while (i < cur.size() && newInterval[0] > cur.get(i)[0]){
    
    
            i++;
        }
        /*按顺序插入*/
        cur.add(i, newInterval);
        res.add(cur.get(0));
        i = 0;
        while (++i < cur.size()){
    
    
            /*比较左端点,加入数据*/
            if(cur.get(i)[0] > res.get(res.size() - 1)[1]) {
    
    
                res.add(cur.get(i));
                continue;
            }
            /*比较右端点谁大,设置区间值*/
            int right = Math.max(res.get(res.size() - 1)[1], cur.get(i)[1]);
            res.set(res.size() - 1, new int[]{
    
    res.get(res.size() - 1)[0], right});
        }
        int[][] ans = new int[res.size()][];
        for(int j = 0; j < res.size(); j++) {
    
    
            ans[j] = res.get(j);
        }
        return ans;
    }

最后一个单词的长度

给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。

Java版本:

    /*
    执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
    内存消耗:36.4 MB, 在所有 Java 提交中击败了97.01%的用户
     */
public static int lengthOfLastWord(String s) {
    
    
		//去除前后空格
        s = s.trim();
        int count = 0;
        for (int i = s.length()-1; i >= 0 && s.charAt(i) != ' '; i--){
    
    
            count++;
        }
        return count;
    }

Python版本:

 # 最后一个单词的长度
class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        # 去除前后空格
        s = s.strip()
        count = 0
        for i in range(len(s)-1, -1, -1):
            if s[i] != ' ':
                count += 1
            else:
                break
        return count

# 测试
s = Solution()
arr = "hello world"
print(s.lengthOfLastWord(arr))

# 答案:
5

螺旋矩阵2

给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

Java解法:

/*
    顺时针赋值
     */

    public static int[][] generateMatrix(int n) {
    
    
        int left = 0 , up = 0;
        int right = n-1 , dowm = n-1;
        int [][]res = new int[n][n];
        int flag = n * n , val = 1;
        while (val <= flag){
    
    
            for (int i = left; i <= right ; i++){
    
    
                res[up][i] = val++;
            }
            up++;
            for (int i = up; i <= dowm ; i++){
    
    
                res[i][right] = val++;
            }
            right--;
            for (int i = right; i >= left ; i--){
    
    
                res[dowm][i] = val++;
            }
            dowm--;
            for (int i = dowm ; i >= up ; i--){
    
    
                res[i][left] = val++;
            }
            left++;
        }
        return res;
    }

Python解法:

class Solution:
       def generateMatrix(self, n: int) -> list:
        left, up = 0, 0
        down, right = n - 1, n - 1
        val = 1
        res = [[0 for i in range(n)] for i in range(n)]
        while val <= n*n:
            for i in range(left, right + 1):
                if val <= n*n:
                    res[up][i] = val
                    val += 1
            up += 1

            for i in range(up, down + 1):
                if val <= n*n:
                    res[i][right] = val
                    val += 1
            right -= 1

            for i in range(right, left - 1, -1):
                if val <= n*n:
                    res[down][i] = val
                    val += 1
            down -= 1

            for i in range(down, up - 1, -1):
                if val <= n*n:
                    res[i][left] = val
                    val += 1
            left += 1

        return res

排列序列

给定 n 和 k,返回第 k 个排列

Java版本:

 /**
     * 思路:数学 + 缩小问题规模
     * 对于 n 个不同的元素(例如数 1, 2,⋯,n),它们可以组成的排列总数目为 n!。
     * 首先确定排列中的首个元素 a1,根据上述的结论,我们可以知道:
     * 以1为a1作为首个的排列一共有 (n-1)! 个;
     * 以2为a1作为首个的排列一共有 (n-1)! 个
     * ...
     * 以n为a1的为首个的排列一共有 (n-1)! 个。
     * 也就是说:
     * 最高位为 1 对应的是第 1 种~共 (n-1)! 种排列,依次类推,最高位为 2 对应的是共 (n-1)!+1 种~共 2(n-1)! 种排列,最高位为 3 对应的是共 2(n-1)!+1 种~共 3(n-1)! 种排列。
     * 想必大家已经发现规律了,我们就借助这个规律来解题。
     * 
     * 回到题目上来,我们怎么求出第 k 个排列?借助上面的思路,我们用一个递归的过程来求解,以 n=4 ,k=7 为例:
     * 固定最高位为 1 不变,有 (n-1)!=6 种排列,固定最高位为 2 不变,也有 (n-1)!=6 种排列,所以 k=7 一定是以 2 开头的。所以我们找到了最高位2。
     * 还剩3个数:1,3,4。更新 k -= 1*(n-1)!=3 , n -= 1 。问题就变成了 nums=[1,3,4], k=3 。以同样的方法找当前最高位,为 1 。
     * 还剩2个数:3,4。更新 k -= 1*(n-1)! =1 , n -= 1 ,问题就变成了 nums=[3,4], k=1 。
     */


    public static String getPermutation(int n, int k) {
    
    
        List<Integer> list = new ArrayList<>();
        for( int i = 1; i <= n; i++ ) {
    
    
            list.add(i);
        }

        StringBuilder res = new StringBuilder();
        while(n > 0) {
    
    
            /*算出多少种排列*/
            int curCom = cal(--n);
            /*相除取整,求出首位*/
            int group = (k-1)/curCom;
            res.append(list.get(group));
            /*删除已用过的数字*/
            list.remove(group);
            /*减去用了的排列种数*/
            k -= (group*curCom);
        }
        return res.toString();
    }

    /*阶乘*/
    private static int cal(int num) {
    
    
        int res = 1;
        for(int i = 1; i <= num; i++) {
    
    
            res *= i;
        }
        return res;
    }

Python版本:

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        nums = [i for i in range(1, n+1)]
        res = str()
        while n > 0:
            # 算出排列种数
            n -= 1
            numcal = self.cal(n)
            # 相除取整,求出下一位,(被除数不为0,这里做判断)
            if k-1 != 0:
                grop = (k - 1) // numcal
            else:
                grop = 0
            # 添加到结果
            res += str(nums[grop])
            # 删除用过的数字
            nums.remove(nums[grop])
            # 减去用了的排列种数
            k = k - grop * numcal

        return res

    # 阶乘
    def cal(self, val: int) -> int:
        res = 1
        for i in range(1, val+1):
            res *= i
        return res

不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?

Java解法:

 /*
    动态规划:
    用 f(i, j)f(i,j) 表示从左上角走到 (i, j)(i,j) 的路径数量,其中 ii 和 jj 的范围分别是 [0, m) 和 [0, n)
    由于我们每一步只能从向下或者向右移动一步,因此要想走到 (i, j),如果向下走一步,那么会从 (i-1, j) 走过来;如果向右走一步,那么会从 (i, j-1) 走过来。
    因此我们可以写出动态规划转移方程:f(i,j)=f(i−1,j)+f(i,j−1)
    初始条件为 f(0,0)=1f(0,0)=1,即从左上角走到左上角有一种方法。最终的答案即为 f(m-1,n-1)f(m−1,n−1)。
    需要注意的是,如果 i=0,那么 f(i-1,j) 并不是一个满足要求的状态,我们需要忽略这一项;同理,如果 j=0,那么 f(i,j−1) 并不是一个满足要求的状态,我们需要忽略这一项
     */

    public static int uniquePaths(int m, int n) {
    
    
        int [][]dp = new int[m][n];
        for (int i = 0 ; i < m ; i++){
    
    
            dp[i][0] = 1;
        }
        for (int j = 0 ; j < n ; j++){
    
    
            dp[0][j] = 1;
        }
        for (int i = 1 ; i < m ; i++){
    
    
            for (int j = 1 ; j < n ; j++){
    
    
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }

Python解法:

# 不同路径
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # 构建dp二维数组
        dp = [[0 for j in range(n)] for i in range(m)]
        for i in range(m):
            dp[i][0] = 1
        for j in range(n):
            dp[0][j] = 1
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]

        return dp[m-1][n-1]

# 测试
s = Solution()
m, n = 3, 7
print(s.uniquePaths(m, n))

# 答案:
28

不同路径 II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

Java解法:

	/*
    动态规划
    */
    public static int  uniquePathsWithObstacles(int[][] obstacleGrid) {
    
    
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int [][]dp = new int[m][n];
        /*初始化列*/
        for (int i = 0; i < m ; i++){
    
    
            if (obstacleGrid[i][0] == 1){
    
    
                break;
            }
            dp[i][0] = 1;
        }
        /*初始化行*/
        for (int j = 0; j < n ; j++){
    
    
            if (obstacleGrid[0][j] == 1){
    
    
                break;
            }
            dp[0][j] = 1;
        }
        for (int i = 1 ; i < m ; i++){
    
    
            for (int j = 1 ; j < n ; j++){
    
    
                /*防止当前点是障碍物*/
                dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];

Python解法:


class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: list) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        # 构建dp二维数组
        dp = [[0 for j in range(n)] for i in range(m)]
        # 初始化列
        for i in range(m):
            if obstacleGrid[i][0] == 1:
                break
            dp[i][0] = 1
        # 初始化行
        for j in range(n):
            if obstacleGrid[0][j] == 1:
                break
            dp[0][j] = 1

        for i in range(1, m):
            for j in range(1, n):
                # 防止当前点是障碍物
                if obstacleGrid[i][j] == 1:
                    dp[i][j] = 0
                else:
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]

        return dp[m-1][n-1]

# 测试
s = Solution()
obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
print(s.uniquePathsWithObstacles(obstacleGrid))

# 答案:
2

最小路径和

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

Java解法:

public static int minPathSum(int[][] grid) {
    
    
        if (grid == null || grid.length == 0 || grid[0].length == 0){
    
    
            return 0;
        }
        int m = grid.length , n = grid[0].length;
        int [][]dp = new int[m][n];
        /*初始化原点,行和列*/
        dp[0][0] = grid[0][0];
        for (int i = 1 ; i < m ; i++){
    
    
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for (int j = 1 ; j < n ; j++){
    
    
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        /*动态规划*/
        for (int i = 1 ; i < m ; i++){
    
    
            for (int j = 1 ; j < n ; j++){
    
    
                dp[i][j] = Math.min(dp[i-1][j] , dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }

Python解法:

# 最小路径和
class Solution:
    def minPathSum(self, grid: list) -> int:
        if not grid or len(grid) == 0 or len(grid[0]) == 0:
            return 0
        m, n = len(grid), len(grid[0])
        dp = [[0 for _ in range(n)] for _ in range(m)]
        # 初始化
        dp[0][0] = grid[0][0]
        for i in range(1, m):
            dp[i][0] = dp[i-1][0] + grid[i][0]
        for j in range(1, n):
            dp[0][j] = dp[0][j-1] + grid[0][j]
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
        return dp[m-1][n-1]



# 测试
s = Solution()
grid = [[1,3,1],[1,5,1],[4,2,1]]
print(s.minPathSum(grid))

# 答案:
7

旋转链表

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

/*
    先将链表闭合成环
    找到相应的位置断开这个环,确定新的链表头和链表尾
     */
    public static ListNode rotateRight(ListNode head, int k) {
    
    
        if (head == null){
    
    
            return null;
        }
        ListNode tail = head;
        int n = 1;  //最终会是链表长度
        while (tail.next != null){
    
    
            tail = tail.next;
            n++;
        }
        /*把尾节点 指向 头结点,这样就形成闭环链表*/
        tail.next = head;
        /*
        找到对应新头节点
        链表头在位置 n-k 处,其中 n 是链表中点的个数,新的链表尾就在头的前面,位于位置 n-k-1。
        */
        ListNode new_tail = head;
        for (int i = 0 ; i < (n - k) % n - 1 ; i++){
    
    
            new_tail = new_tail.next;
        }
        ListNode new_head = new_tail.next;
        // 断开闭环
        new_tail.next = null;
        return new_head;
    }

有效数字

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

Java解法:


	 /*
    遍历目标字符串
    1.判断是否属于数字的0~9区间
    2.遇到点的时候,判断前面是否有点或者E,都需要return false
    3.遇到E的时候,判断前面数字是否合理,是否有E,并把num置为false,防止E后无数字
    4.遇到-+的时候,判断是否是第一个,如果不是第一个判断是否在E后面,都不满足则return false
    5.其他情况都为false
    最后返回num的结果即可
     */

public static boolean isNumber(String s) {
    
    
        if (s == null || s.length() == 0){
    
    
            return false;
        }
        /*num:数字,dot:点,e:指数e*/
        boolean num=false;
        boolean dot=false;
        boolean e=false;
        char []c = s.trim().toCharArray();
        for (int i = 0 ; i < c.length ; i++){
    
    
            if (c[i] >= '0' && c[i] <= '9'){
    
    
                num = true;
            }else if (c[i] == '.'){
    
    
                if (dot || e){
    
    
                    return false;
                }
                dot = true;
            }else if (c[i] == 'e' || c[i] == 'E'){
    
    
                if (!num || e){
    
    
                    return false;
                }
                num = false;
                e = true;
            }else if (c[i] == '+' || c[i] == '-'){
    
    
                if(i != 0 && c[i-1] != 'e' && c[i-1]!='E'){
    
    
                    return false;
                }
            }else{
    
    
                return false;
            }
        }
        return num;
    }

Python解法:

class Solution:
    def isNumber(self, s: str) -> bool:
        if not s or len(s) == 0:
            return False
        num, dot, e = False, False, False
        # 去除空格
        s = s.strip()
        for i in range(len(s)):
            if '0' <= s[i] <= '9':
                num = True
            elif s[i] == '.':
                if dot or e:
                    return False
                dot = True
            elif s[i] == 'e' or s[i] == 'E':
                if not num or e:
                    return False
                num = False
                e = True
            elif s[i] == '+' or s[i] == '-':
                if i != 0 and s[i-1] != 'e' and s[i-1] != 'E':
                    return False
            else:
                return False
        return num


# 测试
s = Solution()
d = "1 "
print(s.isNumber(d))

# 答案:
True

二进制求和

给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。

Java解法:

public static String addBinary(String a, String b) {
    
    
        if(a == null)	return b;
        else if(b == null)	return a;
        int flag = 0;
        int n = Math.max(a.length(), b.length());
        StringBuilder res = new StringBuilder();
        for (int i = 0 ; i < n ; i++){
    
    
            flag += i < a.length() ? (a.charAt(a.length() - i -1) -'0') : 0;
            flag += i < b.length() ? (b.charAt(b.length() - i -1) -'0') : 0;
            res.append((char)(flag % 2 + '0'));
            flag /= 2;
        }
        if (flag > 0){
    
    
            res.append(1);
        }
        return res.reverse().toString();
    }

Python解法:

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        if not a:
            return b
        elif not b:
            return a
        n = max(len(a), len(b))
        flag = 0
        tmp = list()
        for i in range(n):
            if i < len(a):
                flag += int(a[len(a) - i - 1])

            else:
                flag += 0
            if i < len(b):
                flag += int(b[len(b) - i - 1])

            else:
                flag += 0
            tmp.append(str(flag % 2))
            flag //= 2

        if flag > 0:
            tmp.append("1")
        return ''.join(tmp[::-1])

# 测试
s = Solution()
a, b = "11", "1"
print(s.addBinary(a, b))

# 答案:
100

加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

Java解法:

public static int[] plusOne(int[] digits) {
    
    
        for (int i = digits.length - 1 ; i >= 0 ; i--){
    
    
            digits[i]++;
            digits[i] = digits[i] % 10;
            if (digits[i] != 0){
    
    
                return digits;
            }
        }
        digits = new int[digits.length + 1];
        digits[0] = 1;
        return digits;
    }

Python解法:

# 加一
class Solution:
    def plusOne(self, digits: list) -> list:
        for i in range(len(digits)-1, -1, -1):
            digits[i] += 1
            digits[i] %= 10
            if digits[i] != 0:
                return digits
        digits.insert(0, 1)
        return digits

# 测试
s = Solution()
digits = [1,0,9]
print(s.plusOne(digits))

# 测试
[1, 1, 0]

文本左右对齐

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

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

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

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

Java版本:

 /*
    普通情况
    一行放wdCnt个单词, 剩余blank个空格,
    每两个单词之间的空格数为 blank / (count - 1) + mod > 0 ? 1: 0
    mod = blank / (count - 1)
    if(mod > 0) mod--;
    特殊情况1, 如果是最后一行, 单词之间只占一个空格
    特殊情况2, 如果一行只有一个单词, 补齐右边的空格

     */


    public static List<String> fullJustify(String[] words, int maxWidth) {
    
    
        List<String> list = new ArrayList<>();
        int n = words.length;
        int i = 0, j = 0, blank, count, curlen;
        while (i < n){
    
    
            curlen = maxWidth;
            count = 0;
            blank = 0;
            /*求出一行能放的单词数*/
            while (j < n && curlen >= words[j].length()){
    
    
                curlen -= words[j].length();
                count++;
                blank++;
                curlen -= 1; /*减去空格*/
                j++;
            }
            blank += curlen; /*空格数*/
            StringBuilder sb = new StringBuilder();
            /*如果是最后一行,单词之间只占一个空格*/
            if (j >= n){
    
    
                while (i < j){
    
    
                    sb.append(words[i++]).append(" ");
                }
                sb.deleteCharAt(sb.length()-1);
                while (sb.length() < maxWidth){
    
    
                    sb.append(" ");
                }
            }else if (count == 1) {
    
    
                /*如果一行只有一个单词, 补齐右边的空格*/
                while (i < j){
    
    
                    sb.append(words[i++]).append(" ");
                }
                sb.deleteCharAt(sb.length()-1);
                while (sb.length() < maxWidth){
    
    
                    sb.append(" ");
                }
            }else{
    
    
                /*普通情况*/
                int mod = blank % (count - 1);
                int ans = blank / (count - 1);
                while(i < j){
    
    
                    sb.append(words[i++]);
                    int k = ans + (mod > 0 ? 1: 0);
                    mod--;
                    if(i < j) {
    
    
                        for(int l = 0; l < k; l++) {
    
    
                            sb.append(" ");
                        }
                    }
                }
            }
            i = j;
            list.add(sb.toString());
        }
        return list;
    }

Python版本:

# 文本左右对齐
class Solution:
    def fullJustify(self, words: list, maxWidth: int) -> list:
        res = list()
        n = len(words)
        i, j, blank = 0, 0, 0
        while i < n:
            curlen = maxWidth
            count = 0
            blank = 0
            # 求出一行能放的单词数
            while j < n and curlen >= len(words[j]):
                curlen -= len(words[j])
                count += 1
                blank += 1
                curlen -= 1
                j += 1
            blank += curlen
            arr = str()
            if j >= n or count == 1:
                while i < j:
                    arr += words[i] + ' '
                    i += 1
                arr = arr.strip()
                while len(arr) < maxWidth:
                    arr += " "
            else:
                mod = blank % (count - 1)
                ans = blank // (count - 1)
                while i < j:
                    arr += words[i]
                    i += 1
                    k = ans + 1 if mod > 0 else ans
                    mod -= 1
                    if i < j:
                        for l in range(0, k):
                            arr += " "
            i = j
            res.append(arr)
        return res

# 测试
s = Solution()
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
print(s.fullJustify(words, maxWidth))

# 答案:
['This    is    an', 'example  of text', 'justification.  ']

x的平方根

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

Java解法:

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

Python解法:

# x的平方根
class Solution:
    def mySqrt(self, x: int) -> int:
        l, r, ans = 0, x, -1
        while l <= r:
            mid = (l + r) // 2
            if mid * mid <= x:
                ans = mid
                l = mid + 1
            else:
                r = mid - 1
        return ans

# 测试
s = Solution()
print(s.mySqrt(5))

# 答案
2

爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

Java解法:

public static int climbStairs(int n) {
    
    
        if (n == 1 || n == 2){
    
    
            return n;
        }
        int a = 1, b = 2, res = 0;
        for (int i = 3 ; i <= n ; i++){
    
    
            res = a + b;
            a = b;
            b = res;
        }
        return res;
    }

Python解法:

# 爬楼梯
class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1 or n == 2:
            return n
        i, j, res = 1, 2, 0
        for k in range(3, n+1):
            res = i + j
            i = j
            j = res

        return res


# 测试
s = Solution()
print(s.climbStairs(5))

# 测试
8

简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分

Java解法:

	/*
    使用split将字符分开后,要么得到空格,要么得到字符,要么得到..或是.
    使用栈模拟,遍历字符数组,如果是正常字符,就栈入,如果是..则弹出,如果是.或是空则continue
    最后遍历栈,将字符拼接在一起返回即可
     */

    public static String simplifyPath(String path) {
    
    
        Stack<String> stack = new Stack<>();
        String []pathArr = path.split("/");
        for (int i = 0 ; i < pathArr.length; i++){
    
    
            if (pathArr[i].length() == 0|| pathArr[i].equals(".")){
    
    
                continue;
            }
            if (!stack.isEmpty()){
    
    
                if (pathArr[i].equals("..")){
    
    
                    stack.pop();
                }else{
    
    
                    stack.push(pathArr[i]);
                }
            }else{
    
    
                if(!pathArr[i].equals("..")){
    
    
                    stack.push(pathArr[i]);
                }
            }
        }
        StringBuilder res = new StringBuilder();
        if(stack.isEmpty())  {
    
    
            return res.append('/').toString();
        }
        while (!stack.isEmpty()){
    
    
            res.insert(0,stack.pop());
            res.insert(0,'/');
        }
        return res.toString();
    }

Python解法:

# 简化路径
# 将字符串解析成列表,分隔符/,去掉''和.;
# 对..分情况处理:
#   1)当..不在首部,将..及其前一个元素去除
#   2)当..在首部,只将..去除
class Solution:
    def simplifyPath(self, path: str) -> str:
        # 拆成列表,且不能为''和'.'
        pathArr = [p for p in path.split('/') if p not in ['', '.']]
        while '..' in pathArr:
            idx = pathArr.index('..')
            if idx != 0:
                pathArr = pathArr[:idx - 1] + pathArr[idx+1:]
            else:
                pathArr.remove("..")
        res = '/'+'/'.join(pathArr)
        return res
# 测试
s = Solution()
path = "/a/./b/../../c/"
print(s.simplifyPath(path))

# 测试
/c

编辑距离

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

Java解法:

/*
    动态规划
    用 dp[i][j] 表示 A 的前 i 个字母和 B 的前 j 个字母之间的编辑距离。
    当我们获得 dp[i][j-1],dp[i-1][j] 和 dp[i-1][j-1] 的值之后就可以计算出 dp[i][j]。
    dp[i][j-1] 为 A 的前 i 个字符和 B 的前 j - 1 个字符编辑距离的子问题。
    即对于 B 的第 j 个字符,我们在 A 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i][j-1] + 1;

    dp[i-1][j] 为 A 的前 i - 1 个字符和 B 的前 j 个字符编辑距离的子问题。
    即对于 A 的第 i 个字符,我们在 B 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i-1][j] + 1;

    dp[i-1][j-1] 为 A 前 i - 1 个字符和 B 的前 j - 1 个字符编辑距离的子问题。
    即对于 B 的第 j 个字符,我们修改 A 的第 i 个字符使它们相同,那么 dp[i][j] 最小可以为 dp[i-1][j-1] + 1。
    特别地,如果 A 的第 i 个字符和 B 的第 j 个字符原本就相同,那么我们实际上不需要进行修改操作。在这种情况下,dp[i][j] 最小可以为 dp[i-1][j-1]

    对于边界情况,一个空串和一个非空串的编辑距离为 D[i][0] = i 和 D[0][j] = j,D[i][0]
    相当于对 word1 执行 i 次删除操作,D[0][j] 相当于对 word1执行 j 次插入操作
     */
public int minDistance(String word1, String word2) {
    
    
        int n = word1.length();
        int m = word2.length();
        /* 有一个字符串为空串 */
        if (n * m == 0) {
    
    
            return n + m;
        }

        /* DP 数组 */
        int[][] dp = new int[n + 1][m + 1];

        /* 边界状态初始化 */
        for (int i = 0; i < n + 1; i++) {
    
    
            dp[i][0] = i;
        }
        for (int j = 0; j < m + 1; j++) {
    
    
            dp[0][j] = j;
        }
        /* 计算所有 dp 值 */
        for (int i = 1; i < n + 1; i++) {
    
    
            for (int j = 1; j < m + 1; j++) {
    
    
                int res1 = dp[i - 1][j] + 1;
                int res2 = dp[i][j - 1] + 1;
                int res3 = dp[i - 1][j - 1];
                if (word1.charAt(i - 1) != word2.charAt(j - 1)) {
    
    
                    res3 += 1;
                }
                dp[i][j] = Math.min(res1, Math.min(res2, res3));
            }
        }
        return dp[n][m];
    }

Python解法:

# 编辑距离
# 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        m, n = len(word1), len(word2)
        if m == 0 or n == 0:
            return n + m;
        # 创建dp数组,初始化
        dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
        for i in range(m + 1):
            dp[i][0] = i
        for j in range(n + 1):
            dp[0][j] = j
        # 计算
        for i in range(1, m+1):
            for j in range(1, n+1):
                res1 = dp[i-1][j] + 1
                res2 = dp[i][j-1] + 1
                res3 = dp[i-1][j-1]
                if word1[i-1] != word2[j-1]:
                    res3 += 1
                dp[i][j] = min(res1, min(res2, res3))

        return dp[m][n]

# 测试
s = Solution()
word1 = "horse"
word2 = "ros"
print(s.minDistance(word1, word2))

# 答案:
3

最小编辑距离

给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。
示例1
输入
“abc”,“adc”,5,3,2
返回值
2

 /*
    dp[i][j] 表示 word1[0~i] 变成 word2[0~j] 需要的操作次数
     */

    public static int minEditCost (String str1, String str2, int ic, int dc, int rc) {
    
    
        // write code here
        // 如果有一个其中为空
        if (str1 == null){
    
    
            return str2.length() * ic;
        }
        if (str2 == null){
    
    
            return str1.length() * dc;
        }
        int m = str1.length(), n = str2.length();
        // dp[0][0] 表示空字符串变成空字符串的代价(0)
        int[][] dp = new int[m + 1][n + 1];
        // 由 str1 变成空字符串的代价
        for (int i = 1; i <= m; i++){
    
    
            dp[i][0] = i * dc;
        }
        // 由空字符串变成 str2 的代价
        for (int j = 1; j <= n; j++){
    
    
            dp[0][j] = j *ic;
        }
        for (int i = 1; i <= m; i++){
    
    
            for (int j = 1; j <= n; j++){
    
    
                int cur1 = dp[i-1][j] + dc; //dp[i-1][j] 为 dp[i][j] 删除一个元素变成 dp[i-1][j],即加上dc
                int cur2 = dp[i][j-1] + ic;
                int cur3 = dp[i-1][j-1];
                if (str1.charAt(i-1) != str2.charAt(j-1)){
    
    
                    cur3 += rc;
                }
                dp[i][j] = Math.min(Math.min(cur1, cur2), cur3);
            }
        }
        return dp[m][n];
    }

矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。

Java解法:

public static void setZeroes(int[][] matrix) {
    
    
        int m = matrix.length, n = matrix[0].length;
        boolean row = false, col = false;
        /*判断第一行、列有无0*/
        for (int j = 0 ; j < n ; j++) {
    
    
            if (matrix[0][j] == 0){
    
    
                row = true;
                break;
            }
        }
        for (int i = 0 ; i < m ; i++) {
    
    
            if (matrix[i][0] == 0){
    
    
                col = true;
                break;
            }
        }
        /*把第一行和第一列作为 标志位,对应第一行和列被标志了,后续行、列需要置位0*/
        for (int i = 1 ; i < m ; i++){
    
    
            for (int j = 1 ; j < n ; j++){
    
    
                if (matrix[i][j] == 0){
    
    
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }
        /*置零*/
        for (int i = 1 ; i < m ; i++) {
    
    
            for (int j = 1; j < n; j++) {
    
    
                if (matrix[i][0] == 0 || matrix[0][j] == 0){
    
    
                    matrix[i][j] = 0;
                }
            }
        }
        /*对最先的第一行,列做处理*/
        if (row){
    
    
            for (int j = 0 ; j < n ; j++){
    
    
                matrix[0][j] = 0;
            }
        }
        if (col){
    
    
            for (int i = 0 ; i < m ; i++){
    
    
                matrix[i][0] = 0;
            }
        }
    }

Python解法:

# 矩阵置零
class Solution:
    def setZeroes(self, matrix: list) -> list:
        m, n = len(matrix), len(matrix[0])
        row, col = False, False
        # 找第一行是否有0
        for j in range(n):
            if matrix[0][j] == 0:
                row = True
                break
        # 找第一列是否有0
        for i in range(m):
            if matrix[i][0] == 0:
                col = True
                break

        # 把第一行和第一列作为 标志位,对应第一行和列被标志了,后续行、列需要置位0
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0

        # 置0
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0

        # 对最先的第一行,列做处理
        if row:
            for j in range(n):
                matrix[0][j] = 0
        if col:
            for i in range(m):
                matrix[i][0] = 0
        return matrix

# 测试
s = Solution()
matrix = [
          [0,1,2,0],
          [3,4,5,2],
          [1,3,1,5]
        ]
print(s.setZeroes(matrix))

# 答案:
[[0, 0, 0, 0], [0, 4, 5, 0], [0, 3, 1, 0]]

进制转换

给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数
示例1
输入
7,2
返回值
“111”

备注:
M是32位整数,2<=N<=16.

public static String solve (int M, int N) {
    
    
        // write code here
        StringBuilder res = new StringBuilder("");
        String []arr = {
    
    "A","B","C","D","E","F"};
        boolean flag = false;
        if (M < 0){
    
    
            M = -M;
            flag = true;
        }
        while(M != 0){
    
    
            int val = M % N;
            if (val < 10){
    
    
                res.append(val);
            }else{
    
    
                res.append(arr[val - 10]);
            }
            M /= N;
        }
        if (flag){
    
    
            return res.append("-").reverse().toString();
        }else{
    
    
            return res.reverse().toString();
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_42748009/article/details/111358072