Leetcode刷题

文章目录

  • Stack
      • 42 接雨水
      • 84. 柱状图中的最大矩形
      • 二叉树遍历
          • 94. 中序
          • 144. 前序
          • 145. 后序
          • 103. 二叉树的锯齿形层次遍历
          • 173. 二叉树迭代器
  • Heap
      • 215. 数组中的第k大元素
      • 239. 滑动窗口的最大值
  • Tree
      • 113. 路径总和II
  • sort
      • 56. 合并区间
      • 179. 最大数
  • dfs
      • 114. 二叉树转为链表
  • 多线程
      • 1114. 多线程打印
  • Recursion
      • 938. 二叉搜索树的范围和
  • Arrays
      • 33. 搜索旋转数组(总是记不住边界条件怎么写)
      • 48. 旋转图像
      • 121. 买卖股票的最佳时机
      • 162. 寻找峰值
      • 169. 求众数
  • Two pointers
      • 142. 环形链表

Stack

42 接雨水

  1. 找到最高点;
  2. 从两边向最高点遍历;
  3. 设置height为当前高点,如果小于这个点则可以蓄水,水量为height-arr[i]
  • O ( n ) O(n) O(n)
  • O ( 1 ) O(1) O(1)
private static int trap(int[] height) {
        if (height == null || height.length <= 1)
            return 0;
        //找到最高点
        int maxH = height[0];
        int maxIndex = 0;
        for (int i=1; i<height.length; i++) {
            if (height[i] >= maxH) {
                maxH = height[i];
                maxIndex = i;
            }
        }
        //从左边开始遍历
        int max = 0;
        int h = height[0];
        for (int i=1; i<maxIndex; i++) {
            if (height[i] < h) {
                max += h - height[i];
            } else {
                h = height[i];
            }
        }
        h = height[height.length-1];
        for (int i=height.length-1; i>maxIndex; i--) {
            if (height[i] < h) {
                max += h - height[i];
            } else {
                h = height[i];
            }
        }
        return max;
    }

84. 柱状图中的最大矩形

  • 暴力
public static int largestRectangleArea(int[] heights) {
        if (heights == null || heights.length == 0)
            return 0;
        int maxArea = Integer.MIN_VALUE;
        for (int i=0; i<heights.length; i++) {
            int h = heights[i];
            int w = 1;
            int j=i+1;
            while (j < heights.length && heights[j] >= h) {
                w++;
                j++;
            }
            j=i-1;
            while (j >= 0 && heights[j] >= h) {
                w++;
                j--;
            }
            maxArea = Math.max(maxArea, w*h);
        }
        return maxArea;
    }
  • 栈(目前不是很懂,所以没有写上,后面补充)

leetcode原题讲解

  • O ( n ) O(n) O(n)
  • O ( n ) O(n) O(n)

二叉树遍历

94. 中序
  • 递归
public class Solution94 {

    //递归
    List<Integer> res = new ArrayList<>();
    private List<Integer> inorderTraversal(TreeNode root) {
        if (root == null)
            return res;
        if (root.left != null)
            inorderTraversal(root.left);
        res.add(root.val);
        if (root.right != null)
            inorderTraversal(root.right);
        return res;
    }
  • 非递归(栈)
//用栈
private List<Integer> inorderTraversal2(TreeNode root){
    List<Integer> list = new ArrayList<>();
    if (root == null)
        return null;
    Stack<TreeNode> stack = new Stack<>();
    while (root != null || !stack.isEmpty()) {
        if (root != null) {
            stack.push(root);
            root = root.left;
        } else {
            root = stack.pop();
            list.add(root.val);
            root = root.right;
        }
    }
    return list;
}
144. 前序
  • 递归
public class Solution144 {
    //递归
    List<Integer> res = new ArrayList<>();
    private List<Integer> preorderTraversal(TreeNode root) {
        if (root == null)
            return res;
        res.add(root.val);
        if (root.left != null)
            preorderTraversal(root.left);
        if (root.right != null)
            preorderTraversal(root.right);
        return res;
    }
}
  • 非递归
 //非递归
    private static List<Integer> preorderTraversal2(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null)
            return list;
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            if (root != null) {
                list.add(root.val);
                stack.push(root);
                root = root.left;
            } else {
                root = stack.pop();
                root = root.right;
            }
        }
        return list;
    }
145. 后序
  • 递归
	List<Integer> res = new ArrayList<>();
    private List<Integer> postorderTraversal(TreeNode root) {
        if (root == null)
            return res;
        if (root.left != null)
            postorderTraversal(root.left);
        if (root.right != null)
            postorderTraversal(root.right);
        res.add(root.val);
        return res;
    }
  • 非递归
	private static List<Integer> postorderTraversal2(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null)
            return list;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = null;
        TreeNode lastVisit = null;
        stack.push(root);
        while (!stack.isEmpty()) {
            cur = stack.peek();
            //如果cur没有孩子,或者孩子都访问过了,则访问并出栈
            if ((cur.left == null && cur.right == null)||((lastVisit != null && lastVisit == cur.right)||
                    (lastVisit != null && lastVisit == cur.left))) {
                list.add(cur.val);
                lastVisit = cur;
                stack.pop();
            } else {
                if (cur.right != null)
                    stack.push(cur.right);
                if (cur.left != null)
                    stack.push(cur.left);
            }
        }
        return list;
    }
103. 二叉树的锯齿形层次遍历
public class Solution103 {

    //二叉树的锯齿遍历
    private static List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null)
            return res;
        Stack<TreeNode> stack1 = new Stack<>();//存储奇数行
        Stack<TreeNode> stack2 = new Stack<>();//存储奇偶数行
        stack1.push(root);
        while (!stack1.isEmpty() || !stack2.isEmpty()) {
            List<Integer> list = new ArrayList<>();
            if (!stack1.isEmpty()) {
                while (!stack1.isEmpty()) {
                    root = stack1.pop();
                    list.add(root.val);
                    if (root.left != null)
                        stack2.push(root.left);
                    if (root.right != null)
                        stack2.push(root.right);
                }
                res.add(list);
            } else {
                while (!stack2.isEmpty()) {
                    root = stack2.pop();
                    list.add(root.val);
                    if (root.right != null)
                        stack1.push(root.right);
                    if (root.left != null)
                        stack1.push(root.left);
                }
                res.add(list);
            }
        }
        return res;
    }
    
}
173. 二叉树迭代器
class BSTIterator2 {

    Stack<TreeNode> stack = new Stack<>();
    public BSTIterator2(TreeNode root) {
        if (root == null)
            return;
        stack.push(root);
        while (root.left != null){
            stack.push(root.left);
            root = root.left;
        }
    }


    /** @return the next smallest number */
    public int next() {
        TreeNode node = stack.pop();
        if (node.right != null) {
            stack.push(node.right);
            TreeNode tmp = node.right;
            while (tmp.left != null) {
                stack.push(tmp.left);
                tmp = tmp.left;
            }
        }
        return node.val;
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return !stack.isEmpty();
    }
}

Heap

215. 数组中的第k大元素

  1. 建立一个大顶堆
  2. 维持大顶堆的个数为k
  3. 遍历完整个数组的时候堆顶的元素即为所求
public class Solution215 {

    //数组中第k大的元素
    private static int findKthLargest(int[] nums, int k) {
        if (nums==null || nums.length == 0 || k> nums.length)
            return 0;
        //这是一个小顶堆
        PriorityQueue<Integer> pq = new PriorityQueue<>((n1, n2)->n1-n2);
        for (int i=0; i<nums.length; i++) {
            pq.add(nums[i]);
            if (pq.size() > k)
                pq.poll();
        }
        return pq.poll();
    }
 }

239. 滑动窗口的最大值


  • 时间复杂度非常高,
public class Solution239 {
    /**
     * 滑动窗口的最大值
     * */
    //暴力法的时间复杂度为O(nk)
    //堆的时间复杂度是O(nlog2k)
    private static int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length < k)
            return null;
        if (nums.length == 0)
            return new int[0];
        int[] res = new int[nums.length-k+1];
        int index = 0;
        //建大顶堆
        PriorityQueue<Integer> heap = new PriorityQueue<>((n1, n2)->n2-n1);
        for (int i=0; i<nums.length; i++) {
            heap.add(nums[i]);
            if (heap.size() > k) {
                heap.remove(nums[i-k]);
            }
            if (i >= k-1) {
                res[index++] = heap.peek();
            }
        }
        return res;
    }
}
  • dp(没怎么看懂)
    官方解答

Tree

113. 路径总和II

public class Solution113 {


    private static List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> tmp = new ArrayList<>();
        if (root == null)
            return res;
        tmp.add(root.val);
        pathSumUtil(root, sum-root.val, res, tmp);
        return res;
    }

    private static void pathSumUtil(TreeNode root, int sum,
                                    List<List<Integer>> res, List<Integer> tmp) {
        if (root.left == null && root.right == null && 0==sum) {
            //这里为什么这么写?因为地址,后面就改地址了
            res.add(new ArrayList<>(tmp));
            return;
        }
        if (root.left != null) {
            tmp.add(root.left.val);
            pathSumUtil(root.left, sum-root.left.val, res, tmp);
            tmp.remove(tmp.size()-1);
        }
        if (root.right != null) {
            tmp.add(root.right.val);
            pathSumUtil(root.right, sum-root.right.val, res, tmp);
            tmp.remove(tmp.size()-1);
        }
    }
}

sort

56. 合并区间

本题学习怎么二维数组排序。

public class Solution56 {
    //合并区间
    private static int[][] merge(int[][] intervals) {
        List<int[]> res = new ArrayList<>();
        //多维矩阵排序
        if (intervals == null || intervals.length <= 0)
            return res.toArray(new int[0][]);
        // Arrays.sort(intervals, (a, b) -> a[0] - b[0]);// a[0] - b[0]大于0就交换顺序
        // 根据二维数组第一个数字大小按每一行整体排序
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0]-o2[0];
            }
        });
        int i=0;
        while (i < intervals.length) {
            int left = intervals[i][0];
            int right = intervals[i][1];
            // i不能到最后一行,所以要小于(数组的长度 - 1)
            // 判断所在行的right和下一行的left大小,对right重新进行赋最大值,之后再不断进行while循环判断
            while (i < intervals.length - 1 && right >= intervals[i + 1][0]) {
                i++;
                right = Math.max(right, intervals[i][1]);
            }
            res.add(new int[] { left, right });
            i++;
        }
        return res.toArray(new int[0][]);
    }
}

179. 最大数

这里学习自定义比较器

public class Solution179 {
    private static class LargestNumberComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            String s1 = o1+o2;
            String s2 = o2+o1;
            return s2.compareTo(s1);
        }
    }
    //最大数,按首位较大排序
    private static String largestNumber(int[] nums) {
        String[] numsStr = new String[nums.length];
        for (int i=0; i<nums.length; i++) {
            numsStr[i] = String.valueOf(nums[i]);
        }
        Arrays.sort(numsStr, new LargestNumberComparator());
        if ("0".equals(numsStr[0]))
            return "0";
        String res = "";
        for (int i=0; i<numsStr.length; i++)
            res += numsStr[i];
        return res;
    }
}

dfs

114. 二叉树转为链表

class Solution {
    public void flatten(TreeNode root) {
        while (root != null) {
            //左子树为空,直接考虑右子树
            if (root.left == null) {
                root = root.right;
            } else {
                //找到左子树最右边的节点
                TreeNode pre = root.left;
                while (pre.right != null)
                    pre = pre.right;
                //将原来的右子树接到左子树的最右边节点
                pre.right = root.right;
                //将左子树插到右子树的地方
                root.right = root.left;
                root.left = null;
                //考虑下一个节点
                root = root.right;       
            }
        }
    }
}

多线程

1114. 多线程打印

阿里面试问到了这道题,但是我没有这个思路,跪了。

class Foo {

    public Semaphore sema_first_two = new Semaphore(0);
    public Semaphore sema_two_second = new Semaphore(0);

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        sema_first_two.release();
    }

    public void second(Runnable printSecond) throws InterruptedException {

        // printSecond.run() outputs "second". Do not change or remove this line.
        sema_first_two.acquire();
        printSecond.run();
        sema_two_second.release();
    }

    public void third(Runnable printThird) throws InterruptedException {
        sema_two_second.acquire();
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}

Recursion

938. 二叉搜索树的范围和

其实是中序遍历之间的和

public class Solution938 {

    /**
     * 中序遍历之间的节点的和
     * */
    private static int rangeSumBST(TreeNode root, int L, int R) {
        if (root == null)
            return 0;
        if (root.val <= R && root.val >= L) {
            return root.val + rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R);
        } else if (root.val < L) {
            return rangeSumBST(root.right, L, R);
        } else {
            return rangeSumBST(root.left, L, R);
        }
    }
}

Arrays

33. 搜索旋转数组(总是记不住边界条件怎么写)

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length <= 0)
            return -1;
        int l = 0, h = nums.length-1;
        int mid;
        while (l <= h) {
            mid = (l + h)/2;
            if (nums[mid] == target)
                return mid;
            if (nums[mid] < nums[h]) { //说明mid右边单调递增
                if (target <= nums[h] && target >= nums[mid]) {
                    l = mid+1;
                } else {
                    h = mid-1;
                }
            } else { //说明mid左边单调递增
                if (target < nums[mid] && target >= nums[l]) {
                    h = mid-1;
                } else {
                    l = mid+1;
                }
            }
             
        }
        return -1;
    }
}

48. 旋转图像

这题的问题在于每次总是搞不清楚坐标的变换,非常不熟练,因此记录。

//顺线变换坐标
public class Solution {
    private static void rotate(int[][] matrix) {
        for (int i=0; i<matrix.length/2; i++) {
            for (int j=i; j<matrix[0].length-i-1; j++) {
                int tmp = matrix[i][j];
                matrix[i][j] = matrix[matrix.length-1-j][i];
                matrix[matrix.length-1-j][i] = matrix[matrix.length-1-i][matrix.length-1-j];
                matrix[matrix.length-1-i][matrix.length-1-j] = matrix[j][matrix.length-1-i];
                matrix[j][matrix.length-1-i] = tmp;
            }
        }
    }
}

121. 买卖股票的最佳时机

实际也是一道动态规划题。

状态转移方程:第i天的最大收益=max(第i-1天的最大收益,第i天的股价-前i-1天的最小股价)

代码:

private static int maxProfit(int[] prices){
    if (prices == null || prices.length <= 1)
        return 0;
    int maxProfit=0;
    int min = prices[0];
    for (int i=1; i<prices.length; i++) {
        maxProfit = Math.max(maxProfit, prices[i]-min);
        if (prices[i] < min) {
            min = prices[i];
        }
    }
    return maxProfit;
}

162. 寻找峰值

二分法也可以做:

规律:

  • 二分法:
    – 规律一:如果nums[i] > nums[i+1],则在i之前一定存在峰值元素
    – 规律二:如果nums[i] < nums[i+1],则在i+1之后一定存在峰值元素
  • 原因:
    – nums[0] = 负无穷
    – nums[n] = 正无穷

代码:

private static int findPeakElement2(int[] nums) {
       if (nums == null || nums.length <= 1)
           return 0;
       int low = 0, high = nums.length-1;
       int mid;
       while (low <= high) {
           mid = (low + high) >> 1;
           if ((mid == 0 && nums[mid] > nums[mid+1])
                   ||(mid==nums.length-1 && nums[mid] > nums[mid-1])
           ||(nums[mid] > nums[mid+1] && nums[mid] > nums[mid-1])) {
               return mid;
           } else if (nums[mid] > nums[mid+1]) {
               high = mid-1;
           } else {
               low = mid+1;
           }
       }
       return -1;
   }

169. 求众数

这题是easy题,但是没有想到最佳做法,因此记录下来:

class Solution {
    public int majorityElement(int[] nums) {
        int ret = nums[0];
       int count = 1;
       for(int num : nums) {
           if(num != ret) {
               count--;
               if(count == 0) {
                   count = 1;
                   ret = num;
               }
           }
           else
               count++;
       }
       return ret;
    }
}

Two pointers

142. 环形链表

public class Solution142 {

    private static ListNode getIntersect(ListNode head){
        if (head == null || head.next == null) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow)
                return fast;
        }
        return null;
    }

    /**
     * 环形链表
     * */
    private static ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        ListNode fast = getIntersect(head);
        if (fast == null) {
            System.out.println("no cycle");
            return null;
        }
        ListNode ptr1 = head;
        ListNode ptr2 = fast;
        int index = 0;
        while (ptr1 != ptr2) {
            ptr1 = ptr1.next;
            ptr2 = ptr2.next;
            index++;
        }
        return ptr1;
    }
}

你可能感兴趣的:(算法)