LeetCode刷题记录

182 阅读6分钟

分类


链表

  1. 题目: 链表求和
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode l = new ListNode(0), h = l;
        int c = 0;
        while(l1 != null && l2 != null) {
            c += l1.val + l2.val;
            l.val = c % 10;
            c /= 10;
            // 当c>0或者(l1或l2)还未遍历结束的时候继续需要生成节点
            if(c > 0 || l1.next != null || l2.next != null) {
                l.next = new ListNode(0);
                l = l.next;
            }
            l1 = l1.next;
            l2 = l2.next;
        }
        while(l1 != null) {
            c += l1.val;
            l.val = c % 10;
            c /= 10;
            if(c > 0 || l1.next != null) {
                l.next = new ListNode(0);
                l = l.next;
            }
            l1 = l1.next;
        }
        while(l2 != null) {
            c += l2.val;
            l.val = c % 10;
            c /= 10;
            if(c > 0 || l2.next != null) {
                l.next = new ListNode(0);
                l = l.next;
            }
            l2 = l2.next;
        }
        if(c > 0) {
            l.val = c;
        }
        return h;
    }
}
  1. 回文链表
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null)
            return true;
        int len = 0;
        ListNode p = head;
        while(p != null) {
            p = p.next;
            len++;
        }
        p = head;
        // 找到中点
        for(int i = 0; i < len / 2; i++) {
            p = p.next;
        }
        // 单数要走到链表中点右边
        p = len % 2 != 0 ? p.next : p;
        // 反转链表
        ListNode q = null; 
        for(ListNode i = p, pre = null, temp = null; i != null; i = temp) {
            temp = i.next;
            if(temp == null) {
                q = i;
            }
            i.next = pre;
            pre = i;
        }
        p = head;
        // 判断
        while(q != null && p != null) {
            if(q.val != p.val) {
                return false;
            }
            q = q.next;
            p = p.next;
        }
        return true;
    }
}

总结:看了官方的题解,感觉我想复杂了,先遍历一遍链表用ArrayList存储链表的值,然后用两个指针,一个指向数组头,一个指向数组尾,进行判断。

  1. 删除链表中的重复元素
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null)
            return head;
        ListNode p = head, q = null;
        int k = p.val - 1;
        while(p != null) {
            if(k != p.val) {
                k = p.val;
            } else {
                // 删除节点
                q.next = p.next;
                p = q.next;
                continue;
            }
            q = p;
            p = p.next;
        }
        return head;
    }
}
/**
 * 官方题解
 * 作者:LeetCode
 * 来源:力扣(LeetCode)
 */
class Right {
    public ListNode deleteDuplicates(ListNode head) {
    ListNode current = head;
    while (current != null && current.next != null) {
        if (current.next.val == current.val) {
            current.next = current.next.next;
        } else {
            current = current.next;
        }
    }
    return head;
}

总结:这种写法还是不够优雅,官方题解直接用一个ListNode对象就解决了。

  1. 环形链表
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null)
            return false;
        ArrayList<ListNode> store = new ArrayList<>(200);
        while(head != null) {
            if(store.contains(head)) {
                return true;
            }
            store.add(head);
            head = head.next;
        }
        return false;
    }
}
  1. 剑指 Offer 06. 从尾到头打印链表
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        LinkedList<Integer> stack = new LinkedList<>();
        while (head != null) {
            stack.push(head.val);
            head = head.next;
        }
        int[] a = new int[stack.size()];
        for (int i = 0; i < a.length; i++) {
            a[i] = stack.pop();
        }
        return a;
    }
}

很简单的一道题,思路是用栈存储链表的元素,再利用栈先进后出的性质,获取转置后的链表元素

  1. 两数相加
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if (l1 == null && l2 == null)
            return null;
        ListNode curr = new ListNode(0), head = curr, pre = null;
        int a = 0;
        while (l1 != null && l2 != null) {
            a += l1.val + l2.val;
            if (pre != null) {
                curr = new ListNode(a % 10);
                pre.next = curr;
            } else {
                curr.val = a % 10; 
            }
            pre = curr;
            a /= 10;
            l1 = l1.next;
            l2 = l2.next;
        }
        while (l1 != null) {
            a += l1.val;
            curr = new ListNode(a % 10);
            pre.next = curr;
            pre = curr;
            a /= 10;
            l1 = l1.next;
        }
        while (l2 != null) {
            a += l2.val;
            curr = new ListNode(a % 10);
            pre.next = curr;
            pre = curr;
            a /= 10;
            l2 = l2.next;
        }
        if (a > 0) {
            curr = new ListNode(a % 10);
            pre.next = curr;
        }
        return head;
    }
}

这道题和链表求和一模一样,官方题解写得很优雅!

  1. 剑指 Offer 18. 删除链表的节点
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        if (head == null)
            return null;
        if (head.val == val) {
            return head.next;
        }
        ListNode p = head.next, q = head;
        while (p != null) {
            if (p.val == val) {
                q.next = p.next;
                break;
            }
            q = p;
            p = p.next;
        }
        return head;
    }
}

  1. 剑指 Offer 09. 用两个栈实现队列
class CQueue {

    private Deque<Integer> stack1;
    private Deque<Integer> stack2;

    public CQueue() {
        stack1 = new LinkedList<>();
        stack2 = new LinkedList<>();
    }
    
    public void appendTail(int value) {
        stack1.push(value);
    }
    
    public int deleteHead() {
        if(stack2.isEmpty()) {
            while(!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        if(stack2.isEmpty()) {
            return -1;
        } else {
            return stack2.pop();
        }
    }
}

这里是看了官方的题解后修改的,我原来想到的是在删除时把stack1的元素装到stack2里, 拿到队列第一个元素后再把stack2的元素装回stack1。看了官方的题解,很巧妙!


  1. 二叉树的中序遍历
/**
 * 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> list = new ArrayList<>();
        if (root == null)
            return list;
        inOrder(root,list);
        return list;
    }

    public void inOrder(TreeNode p, List<Integer> list) {
        if (p != null) {
            inOrder(p.left, list);
            list.add(p.val);
            inOrder(p.right, list);
        }
    }
}

此题还有迭代,Morris算法等解法

  1. 二叉树的层序遍历
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null)
            return res;
        Deque<TreeNode> queue = new ArrayDeque<>();
        TreeNode curr = root, p = root;
        int index = -1;
        while (curr != null) {
            if (curr == p) {
                res.add(new ArrayList<>());
                index++;
                p = null;
            }
            if (curr.left != null)
                queue.offer(curr.left);
            if (curr.right != null)
                queue.offer(curr.right);
            res.get(index).add(curr.val);
            if (p == null) {
                if (curr.left != null)
                    p = curr.left;
                else if (curr.right != null)
                    p = curr.right;
            }
            if (!queue.isEmpty())
                curr = queue.poll();
            else
                curr = null;
        }
        return res;
    }
}
  1. 二叉树的层次遍历 II
class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null)
            return res;
        Deque<TreeNode> q = new LinkedList<>();
        q.offer(root);
        TreeNode temp = null;
        while (!q.isEmpty()) {
            res.add(new ArrayList<>());
            int currentSize = q.size();
            for (int i = 0; i < currentSize; i++) {
                temp = q.poll();
                res.get(res.size() - 1).add(temp.val);
                if (temp.left != null)
                    q.offer(temp.left);
                if (temp.right != null)
                    q.offer(temp.right);
            }
        }
        
        int size = res.size(), count = size / 2;
        List<Integer> swap = null;
        for (int i = 0; i < count; i++) {
            int t = size - 1 - i;
            swap = res.get(i);
            res.set(i, res.get(t));
            res.set(t, swap);
        }
        return res;
    }
}

利用队列的性质,进行层次遍历,可以参考广度优先搜索

  1. 左叶子之和
class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null)
            return 0;
        int sum = 0;
        if (root.right != null) {
            // 找右子树的叶子节点
            sum += sumOfLeftLeaves(root.right);
        }
        if (root.left != null) {
            // 找左子树的叶子节点
            sum += sumOfLeftLeaves(root.left);
            // 确定左孩子是否为叶子节点
            sum += helper(root.left);
        }
        return sum;
    }

    public int helper(TreeNode left) {
        // 确认是否为叶子节点
        if (left.left == null && left.right == null) {
            return left.val;
        }
        return 0;
    }
}
  1. 剑指 Offer 55 - I. 二叉树的深度
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null)
            return 0;
        return 1 + max(maxDepth(root.left), maxDepth(root.right));
    }

    public static int max(int a, int b) {
        return a > b ? a : b;
    }
}

利用递归,直接秒了。这道题有多种做法,官方题解就很详细


  1. 剑指 Offer 27. 二叉树的镜像
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if (root == null)
            return null;
        helper(root);
        return root;
    }

    public void helper(TreeNode root) {
        swap(root);
        if (root.left != null)
            helper(root.left);
        if (root.right != null)
            helper(root.right);
    }

    public void swap(TreeNode root) {
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

  1. 剑指 Offer 40. 最小的k个数
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] ans = new int[k];
        int size = arr.length - 1;
        for (int i = (arr.length >> 1) - 1; i >= 0; i--)
            helper(arr,i,size);
        for (int i = arr.length - 1; i >= 1; i--) {
            exchange(arr,0,size);
            size--;
            helper(arr, 0, size);
        }
        for (int i = 0; i < k; i++)
            ans[i] = arr[arr.length - i - 1];
        return ans;
    }

    private void helper(int[] heap, int i, int size) {
        int left = ((i + 1) << 1) - 1, right = (i + 1) << 1, large;
        if (left <= size && heap[i] > heap[left])
            large = left;
        else
            large = i;
        if (right <= size && heap[large] > heap[right])
            large = right;
        if (large != i) {
            exchange(heap,i,large);
            helper(heap, large, size);
        }
    }

    private void exchange(int[] heap, int i, int j) {
        int t = heap[i];
            heap[i] = heap[j];
            heap[j] = t;
    }
}

构造最小堆!


其他

  1. 剑指 Offer 10- I. 斐波那契数列
class Solution {
    public int fib(int n) {
        if (n == 0 || n == 1)
            return n;
        final int mod = 1000000007;
        int ans = 0, pre = 0, post = 1;
        for (int i = 1; i < n; i++) {
            ans = pre + post;
            if (ans > mod)
                ans %= mod;
            pre = post;
            post = ans;
        }
        return ans;
    }
}
  1. 剑指 Offer 11. 旋转数组的最小数字
class Solution {
    public int minArray(int[] numbers) {
        Arrays.sort(numbers);
        return numbers[0];
    }
}

其实就是求数组的最小值

class Solution {
    public int maximum69Number (int num) {
        String s = String.valueOf(num);
        return Integer.valueOf(s.replaceFirst("6", "9")); 
    }
}