leetcode 随笔21

这篇博客记录了作者在LeetCode上解题的心得,包括螺旋矩阵(54、59题)、第k个排列(60题)、简化路径(71题)、矩阵置零(73题)、组合(77题)、搜索旋转排序数组 II(81题)、分隔链表(86题)、二叉树的中序遍历(94题)、用 Rand7() 实现 Rand10(470题)以及机器人能否返回原点(657题)和朋友圈(547题)。文章中提到了解题思路、遇到的问题以及解决方案。
摘要由CSDN通过智能技术生成

8.21

54. 螺旋矩阵

难度中等

这个题很像前两天华为的一个笔试题,当时自己没有完全通过,现在碰巧遇到,发现当时自己的循环条件写错了,在处理最后剩下的一行或一列的时候也出错了。有点可惜。

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> ans = new ArrayList<>();
        if(matrix.length == 0){
            return ans;
        }
        int min = Math.min(matrix.length, matrix[0].length);
        int loop = min / 2;
        if((min & 1) == 0){
            loop--;
        }
        for(int i = 0;i <= loop;i++){
            handle(matrix, ans, i);
        }
        return ans;
    }

    public void handle(int[][] matrix, List<Integer> ans, int start){
        int beginX = start, beginY = start;
        int endX = matrix.length - start - 1;
        int endY = matrix[0].length - start - 1;

        for(int i = beginY;i <= endY;i++){//第一行
            ans.add(matrix[beginX][i]);
        }
        if(beginX == endX){
            return ;
        }
        for(int i = beginX + 1;i <= endX;i++){//最后一列
            ans.add(matrix[i][endY]);
        }

        if(beginY == endY){
            return ;
        }

        for(int i = endY - 1;i >= beginY;i--){//最后一行
            ans.add(matrix[endX][i]);
        }

        for(int i = endX - 1;i > beginX;i--){//第一列
            ans.add(matrix[i][beginY]);
        }
    }
}

59. 螺旋矩阵 II

难度中等

操作和上一题大体一致,稍微修改一下就行。

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] matrix = new int[n][n];
        int loop = (n & 1) == 0 ? n / 2 - 1 : n / 2;
        int num = 1;
        for(int i = 0;i <= loop;i++){
            num = handle(matrix, i, num);
        }
        return matrix;
    }


    public int handle(int[][] matrix, int start, int num){
        int beginX = start, beginY = start;
        int endX = matrix.length - start - 1;
        int endY = matrix[0].length - start - 1;

        for(int i = beginY;i <= endY;i++){//第一行
            matrix[beginX][i] = num++;
        }

        if(beginX == endX){
            return num;
        }
        
        for(int i = beginX + 1;i <= endX;i++){//最后一列
            matrix[i][endY] = num++;    
        }

        if(beginY == endY){
            return num;
        }

        for(int i = endY - 1;i >= beginY;i--){//最后一行
            matrix[endX][i] = num++;
        }

        for(int i = endX - 1;i > beginX;i--){//第一列
            matrix[i][beginY] = num++;
        }

        return num;
    }
}

60. 第k个排列

难度中等

自己尝试写了很久也没写出来。然后去看了题解,看了一段时间也没有看懂。如果有人有思路的话可以告诉我一下吗?

class Solution {
    public String getPermutation(int n, int k) {
        StringBuilder sb = new StringBuilder();

        List<Integer> nums = new ArrayList<>();
        for(int i = 0;i < n;i++){
            nums.add((i + 1));
        }

        int currUnitCount = 1;
        int currRemain = k - 1;

        for(int i = 0;i < n;i++){//n的阶乘
            currUnitCount = currUnitCount * (n - i);
        }
        
        for(int i = 0;i < n;i++){
            currUnitCount = currUnitCount / (n - i);
            sb.append(nums.remove(currRemain / currUnitCount));
            currRemain = currRemain % currUnitCount;
        }
        
        return sb.toString();
    }
}

71. 简化路径

难度中等

先借助split函数将path拆解。将有效的地址放入list当中,之后再将其拼接起来。

class Solution {
    public String simplifyPath(String path) {
        String[] arr = path.split("/");

        List<String> list = new LinkedList<>();
        for(String str : arr){
            if(!str.equals("") && !str.equals(".")){
                if(str.equals("..")){
                    if(!list.isEmpty()){
                        list.remove(list.size() - 1);
                    }
                }else{
                    list.add(str);
                }
            }
        }
        StringBuilder sb = new StringBuilder("/");
        for(String str : list){
            sb.append(str + "/");
        }

        return sb.length() == 1 ? "/" : sb.toString().substring(0, sb.length() - 1);
    }
}

73. 矩阵置零

难度简单

尝试O(1)的空间复杂度。想了一种用临时值来标识这个位置应该被更改。但是在写的时候就想到了,如果这样的前提是数组中没有出现临时值。抱着试一试的心态跑了几次,发现测试用例中应该都出现了比较经典的数字。但是别的好像没什么思路。

class Solution {
    int changeVal = Integer.MIN_VALUE;
    public void setZeroes(int[][] matrix) {
        int rows = matrix.length;
        int columns = matrix[0].length;


        for(int i = 0;i < rows;i++){
            for(int j = 0;j < columns;j++){
                if(matrix[i][j] == 0){
                    changeMatrix(matrix, i, j);
                }
            }
        }

        for(int i = 0;i < rows;i++){
            for(int j = 0;j < columns;j++){
                if(matrix[i][j] == changeVal){
                    matrix[i][j] = 0;
                }
            }
        }
    }

    public void changeMatrix(int[][] matrix, int row, int column){
        for(int i = 0;i < matrix.length;i++){
            if(matrix[i][column] != 0){
                matrix[i][column] = changeVal;
            }
        }

        for(int i = 0;i < matrix[0].length;i++){
            if(matrix[row][i] != 0){
                matrix[row][i] = changeVal;
            }
        }
    }
}

参看了题解,可以把对应的行和列的开头标识为0,表示这行或这列需要被更改为0。

知道是这么个思想,但是写起来需要注意的事项却很多。试了很多错,终于把代码完整地写出来了。

class Solution {
    public void setZeroes(int[][] matrix) {
        int rows = matrix.length;
        int columns = matrix[0].length;

        boolean change = matrix[0][0] == 0;
        boolean changeRow = false;
        boolean changeColumn = false;
        boolean singleChange = false;
        for(int i = 0;i < rows;i++){
            for(int j = 0;j < columns;j++){
                if(matrix[i][j] == 0){
                    if(i == 0){
                        changeRow = true;
                    }
                    if(j == 0){
                        changeColumn = true;
                    }
                    singleChange = true;
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for(int j = columns - 1;j > 0;j--){
            if(matrix[0][j] == 0){
                for(int m = 0;m < rows;m++){
                    matrix[m][j] = 0;
                }
            }
        }
        
        
        for(int i = 1;i < rows;i++){
            if(matrix[i][0] == 0){
                for(int m = 0;m < columns;m++){
                    matrix[i][m] = 0;
                }
            }
        }
        if(changeRow){
            for(int m = 0;m < columns;m++){
                matrix[0][m] = 0;
            }
        }
        if(changeColumn){
            for(int m = 0;m < rows;m++){
                matrix[m][0] = 0;
            }
        }

        if(change || (singleChange && (rows == 1 || columns == 1))){
            for(int m = 0;m < rows;m++){
                matrix[m][0] = 0;
            }

            for(int m = 0;m < columns;m++){
                matrix[0][m] = 0;
            }
        }
    }
}

77. 组合

难度中等

最开始想复杂了,一直卡在循环。其实没有那么复杂。

class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> ans = new LinkedList<>();

        if(n < 1 || n < k){
            return ans;
        }
        List<Integer> temp = new LinkedList<>();
        f(ans, temp, n, k, 1);
        return ans;
    }

    public void f(List<List<Integer>> ans, List<Integer> temp,int n, int k, int begin){
        if(temp.size() == k){
            ans.add(new LinkedList<>(temp));
            return; 
        }

        for(int i = begin;i <= n;i++){
            temp.add(i);
            f(ans, temp, n, k, i + 1);
            temp.remove(temp.size() - 1);
        }
    }
}

81. 搜索旋转排序数组 II

难度中等

这类问题之前都做过几遍了,现在来写还是会踩到坑。继续练吧。

class Solution {
    public boolean search(int[] nums, int target) {
        if(nums.length == 0){
            return false;
        }
        return search(nums, target, 0, nums.length - 1);
    }

    public boolean search(int[] nums, int target, int left, int right){
        int mid;
        while(left <= right){
            mid = left + (right - left) / 2;
            
            if(nums[mid] == target){
                return true;
            }else if(nums[left] == nums[mid]){
                left++;
            }else if(nums[mid] > nums[left]){//左边是有序的
                if(target < nums[mid]  && target >= nums[left]){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }else{//右边是有序的
                if(target > nums[mid] && target <= nums[right]){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }
        }
        return false;
    }
}

86. 分隔链表

难度中等

最开始看错了题意,我以为是一个类似于涂色游戏,也就是三指针的题。但是实质上只需要两个指针就可以实现了。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode partition(ListNode head, int x) {
        if(head == null){
            return head;
        }

        ListNode lessHead = new ListNode(1);
        ListNode moreHead = new ListNode(1);

        ListNode lessNode = lessHead;
        ListNode moreNode = moreHead;

        ListNode node = head;
        while(node != null){
            if(node.val >= x){
                moreNode.next = node;
                moreNode = moreNode.next;
            }else{
                lessNode.next = node;
                lessNode = lessNode.next;
            }
            node = node.next;
        }

        lessNode.next = null;
        moreNode.next = null;
        if(moreHead.next != null){
            lessNode.next = moreHead.next;
        }
        return lessHead.next;
    }
}

顺便贴上自己最开始写的三个指针实现类似填色游戏。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode partition(ListNode head, int x) {
        if(head == null){
            return head;
        }

        ListNode lessHead = new ListNode(1);
        ListNode moreHead = new ListNode(1);
        ListNode valHead = new ListNode(1);

        ListNode lessNode = lessHead;
        ListNode moreNode = moreHead;
        ListNode valNode = valHead;

        ListNode node = head;
        while(node != null){
            if(node.val == x){
                valNode.next = node;
                valNode = valNode.next;
            }else if(node.val > x){
                moreNode.next = node;
                moreNode = moreNode.next;
            }else{
                lessNode.next = node;
                lessNode = lessNode.next;
            }
            node = node.next;
        }



        lessNode.next = null;
        moreNode.next = null;
        valNode.next = null;

        if(lessHead.next == null){//没有比x小的部分
            if(valHead.next == null){//只有比x大的部分
                return moreNode.next;
            }else{//有等于x的部分
                valNode.next = moreHead.next;
                return valHead.next;
            }
        }

        if(valHead.next == null){//没有等于x的部分
            if(moreHead.next != null){//有大于x的部分,直接拼接
                lessNode.next = moreHead.next;
            }
            return lessHead.next;
        }

        //三个部分都有
        lessNode.next = valHead.next;
        valNode.next = moreHead.next;
        return lessHead.next;
    }

}

8.22

94. 二叉树的中序遍历

难度中等

递归实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new LinkedList<>();
        
        inorderTraversal(root, ans);
        return ans;
    }

    public void inorderTraversal(TreeNode root, List<Integer> ans){
        if(root == null){
            return ;
        }
        inorderTraversal(root.left, ans);
        ans.add(root.val);
        inorderTraversal(root.right, ans);
    }
}

迭代实现。借助一个栈,优先弹出后加入的节点。树的遍历还有一种特殊的方法,当时在左神的课上听过,但是现在有点忘了。是通过修改树的结构,在得到对应的节点之后再把树的结构复原。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            ans.add(cur.val);
            cur = cur.right;
        }
        
        return ans;
    }
}

8.24

470. 用 Rand7() 实现 Rand10()

难度中等

单独只调用一次rand7是不能实现rand10的。所以需要两次调用rand7,来保证rand10每次取出的值的概率都是一样的。

/**
 * The rand7() API is already defined in the parent class SolBase.
 * public int rand7();
 * @return a random integer in the range 1 to 7
 */
class Solution extends SolBase {
    public int rand10() {
        int i = 0;
        int j = 0;
        int num = 41;
        while(num > 40){//拒绝策略,直到拿到符合条件的数值
            //得到1-40的随机数,得到每个数的概率都相等
            i = rand7();
            j = rand7();
            num = i + (j - 1) * 7;
        }
        return 1 + (num - 1) % 10;
    }
}

8.28

657. 机器人能否返回原点

难度简单

用两个int表示偏差量即可。最后两个偏差量都为0,则说明可以回到原点。

class Solution {
    public boolean judgeCircle(String moves) {
        if(moves == null || moves.length() == 0){
            return true;
        }
        int[] count = new int[2];//0表示左右,1表示上下
        
        for(char c : moves.toCharArray()){
            switch(c){
                case 'L':
                    count[0]--;
                    break;
                case 'R':
                    count[0]++;
                    break;
                case 'U':
                    count[1]++;
                    break;
                case 'D':
                    count[1]--;
                    break;
                default:
                    break;
            }
        }
        for(int num : count){
            if(num != 0){
                return false;
            }
        }
        return true;
    }
}

547. 朋友圈

难度中等

深度遍历的思想,把同属于一个朋友圈的所有人找出来,借助一个布尔数组进行标记。

class Solution {
    public int findCircleNum(int[][] M) {
        int len = M.length;
        boolean[] flag = new boolean[len];
        int ans = 0;

        for(int i = 0;i < len;i++){
            if(flag[i]){
                continue;
            }
            ans++;
            flag[i] = true;
            for(int j = i + 1;j < len;j++){
                if(M[i][j] == 1 && !flag[j]){
                    flag[j] = true;
                    dfs(M, flag, j);
                }
            }
        }
        return ans;
    }


    public void dfs(int[][] M, boolean[] flag, int index){
        for(int i = 0;i < M.length;i++){
            if(M[index][i] == 1 && !flag[i]){
                flag[i] = true;
                dfs(M, flag, i);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值