LeetCode 24, 29, 73

101 阅读4分钟

LeetCode 24 Swap Nodes in Pairs

链接:leetcode.com/problems/sw…

方法1:普通做法

时间复杂度:O(n)

空间复杂度:O(1)

想法:我感觉我现在做链表的题还真是挺喜欢先开一个dummy再开一个tail,然后tail首先指向dummy,然后一路把这个以dummy为开头的链表建立起来。这个题我也是这么写的,主要是在最后有个地方需要注意一下。就是说假如两个一组两个一组地交换完了,然后原本链表里总共节点个数是奇数个,那么这时候在最后一个节点,因为我们是从另一个dummy链表连过去的,这时候p.next会是null,会直接跳出while循环,那么在循环外面需要来一句tail.next = p,把这个节点也加进新链表,不然的话就漏了。

代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        
        ListNode dummy = new ListNode(0, head);
        ListNode tail = dummy;
        ListNode p = head;
        
        while (p != null && p.next != null) {
            ListNode q = p.next;
            ListNode nextP = q.next;
            tail.next = q;
            q.next = p;
            p.next = null;
            tail = tail.next.next;
            p = nextP;
        }
        
        tail.next = p;
        
        return dummy.next;
    }
}

方法2:也是普通做法

时间复杂度:O(n)

空间复杂度:O(1)

想法:我看着花花酱是这么做的zxi.mytechroad.com/blog/list/l… ,就是直接在原本的链表上面动,而不是说新开一个dummy然后大家往那边挪。这做法的好处是不会漏节点,循环结束的时候就是原本链表不能再进行两两swap操作了,反正是在原链表上做的,因此后面的节点还是带着。

代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        
        ListNode dummy = new ListNode(0, head);
        head = dummy;
        
        while (head != null && head.next != null && head.next.next != null) {
            ListNode n1 = head.next;
            ListNode n2 = n1.next;
            
            n1.next = n2.next;
            n2.next = n1;
            
            head.next = n2;
            head = n1;
        }
        
        return dummy.next;
    }
}

LeetCode 29 Divide Two Integers

链接:leetcode.com/problems/di…

方法:位运算

时间复杂度:O(1)

空间复杂度:O(1)

想法:学习自lee哥leetcode.com/problems/di… ,我感觉对我来说他写的第二种写法比较好理解,首先java里面int的范围是[-231,231-1],这就导致了假如说被除数是Integer.MIN_VALUE,除数是-1,此时int范围内无法表示这个正整数,按照题目所说,如果超出范围就返回Integer.MAX_VALUE,因此首先把这个给判断并返回。另外,这种方法的想法在于,我们知道最后结果是一个整数,任何一个整数,都可以用系数为0或1的2i的线性组合来构成。就是任何整数都可以被二进制化。那么,我们就枚举位数i,从31到0,假设说a右移i位的时候,有(a >>> i) - b >= 0,这说明这个结果,比2i多,因此2i这个地方的系数为1。那么既然a右移i位有这个结果,也就说明b乘以(1<<i)<=a。那么结果就加上2的i次方,即(1<<i),然后a里面减去这个b右移的数。基本思路就是这样。这里if ((a >>> i) - b >= 0)不能写成if ((a >>> i) >= b),因为divisor可以取Integer.MIN_VALUE,然后b是它的绝对值,求绝对值的时候爆了int的范围了,溢出了1,所以b其实还是Integer.MIN_VALUE,考虑到这种情况,假如写if ((a >>> i) >= b),就会出现左边不管是多少肯定都>= b的现象,但这样求得的得数是不对的。改为if ((a >>> i) - b >= 0)可以处理掉这种corner case。

代码:

class Solution {
    public int divide(int dividend, int divisor) {
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }
        
        int a = Math.abs(dividend), b = Math.abs(divisor), res = 0;
        
        for (int i = 31; i >= 0; i--) {
            if ((a >>> i) - b >= 0) {
                res += (1 << i);
                a -= (b << i);
            }
        }
        
        return (dividend > 0) == (divisor > 0) ? res : -res;
    }
}

LeetCode 73 Set Matrix Zeroes

链接:leetcode.com/problems/se…

方法:使用矩阵本身做哈希表

时间复杂度:O(mn)

空间复杂度:O(1)

想法:题目说如果矩阵当中但凡有个地方是0,就把它的那一行和列全都置0。最基本的做法是空间复杂度O(mn),反正就是遍历一遍每个位置记下来是不是应该置为0。稍作改进是O(m+n),开两个数组一个管行,一个管列,遍历一遍记录下来哪一行哪一列应该被置0。题目说这俩方法都不行,你能不能再省点空间in-place地做。能,就是先遍历第一行,遍历第一列,先记下来第一行是不是应该被置为0,第一列是不是应该被置为0,然后行列都只从1开始遍历,拿着矩阵的第一行和第一列当哈希表,如果matrix[i][j] == 0,那就在matrix[i][0]和matrix[0][j]这俩地方标上0,证明该行该列应该置0,然后再来一波遍历实际把里面该置为0的置为0,最后用一开始存下来的俩变量研究一下第一行和第一列应不应该被置0,如果应该,就去做。

代码:

class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        boolean row0 = false, col0 = false;
        
        for (int i = 0; i < m; i++) {
            col0 |= (matrix[i][0] == 0);
        }
        for (int j = 0; j < n; j++) {
            row0 |= (matrix[0][j] == 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 (col0) {
            for (int i = 0; i < m; i++) {
                matrix[i][0] = 0;
            }
        }
        if (row0) {
            for (int j = 0; j < n; j++) {
                matrix[0][j] = 0;
            }
        }
    }
}