LeetCode one question per day (continuous update)

March 1st

225. Use queues to implement stacks

Use queues to implement the following operations of the stack:

  • push(x) - push element x onto the stack
  • pop() - remove the top element of the stack
  • top() - Get the top element of the stack
  • empty() - returns whether the stack is empty

Note:
You can only use the basic operations of the queue--that is, push to back, peek/pop from front, size, and is empty operations are legal.
The language you are using may not support queues. You can use list or deque (double-ended queue) to simulate a queue, as long as it is a standard queue operation.
You can assume that all operations are valid (for example, no pop or top operations are called on an empty stack).

        For this question, my approach is not the simplest approach, but it is the easiest approach to understand.

Idea: When 
adding elements to a queue, when popping elements, you need to put the elements in the queue into another queue, and popping the last element. 
Both queues always keep only one queue with data.

class MyStack {
    Queue<Integer> queueA;
    Queue<Integer> queueB;

    /** Initialize your data structure here. */
    public MyStack() {
        queueA = new LinkedList<>();
        queueB = new LinkedList<>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        if (!queueA.isEmpty()) {
            queueA.offer(x);
        } else {
            queueB.offer(x);
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        if (!queueA.isEmpty()) {
            while (queueA.size() > 1) {
                queueB.offer(queueA.poll());
            }
            return queueA.poll();
        } else {
            while (queueB.size() > 1) {
                queueA.offer(queueB.poll());
            }
            return queueB.poll();
        }
    }
    
    /** Get the top element. */
    public int top() {
        int top = 0;
        if (!queueA.isEmpty()) {
            while (queueA.size() > 1) {
                queueB.offer(queueA.poll());
            }
            top = queueA.poll();
            queueB.offer(top);
        } else {
            while (queueB.size() > 1) {
                queueA.offer(queueB.poll());
            }
            top = queueB.poll();
            queueA.offer(top);
        }
        return top;
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queueA.isEmpty() && queueB.isEmpty();
    }
}

March 2

Interview Question 24. Reverse Linked List

Reverse a singly linked list.

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

        Classic questions, not many BBs. The focus is on the understanding of recursion.

public class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        //这里的cur就是最后一个节点
        ListNode p = reverseList(head.next);
        //如果链表是 1->2->3->4->5,那么此时的cur就是5
		//而head是4,head的下一个是5,下下一个是空
		//所以head.next.next 就是5->4
        head.next.next = head;
        //断开当前连接
        head.next = null;
        //每层递归函数都返回cur,也就是最后一个节点
        return p;
    }
}

March 3

Interview Question 10.01. Merge sorted arrays

Given two sorted arrays A and B, there is enough buffer space at the end of A to accommodate B. Write a method to merge B into A and sort.

Initialize the number of elements of A and B to m and n, respectively.

示例:

输入:
A = [1,2,3,0,0,0], m = 3
B = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]
public class Solution {
    public void merge(int[] A, int m, int[] B, int n) {
        //方法1:利用Collections.sort进行排序(执行用时:3 ms)
        /*
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            list.add(A[i]);
        }
        for (int i = 0; i < n; i++) {
            list.add(B[i]);
        }
        Collections.sort(list);
        for (int i = 0; i < m + n; i++) {
            A[i] = list.get(i);
        }
         */
        //方法2:利用Arrays.sort进行排序(执行用时:1 ms)
        /*
        for (int i = 0; i < n; i++) {
            A[m + i] = B[i];
        }
        Arrays.sort(A);
         */
        //方法3:逆向双指针(执行用时:0 ms)
        int i = m - 1, j = n - 1, idx = m + n - 1;
        while (j >= 0) {
            if (i < 0 || B[j] >= A[i]) {
                A[idx--] = B[j--];
            } else {
                A[idx--] = A[i--];
            }
        }
    }
}

March 4

994. Rotten Orange

In a given grid, each cell can have one of the following three values:

  • The value 0 represents an empty cell;
  • The value 1 represents fresh oranges;
  • The value 2 represents rotten oranges.

Every minute, any fresh orange adjacent to the rotten orange (in 4 positive directions) will rot.

Returns the minimum number of minutes that must elapse until there are no fresh oranges in the cell. If it is not possible, return -1.

示例 1:
输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4

        The classic breadth first search problem, the code is as follows:

public class Solution {
    //分别对应 左、下、右、上 四个方向
    int[] dr = new int[]{-1, 0, 1, 0}; //行方向
    int[] dc = new int[]{0, -1, 0, 1}; //列方向

    public int orangesRotting(int[][] grid) {
        int R = grid.length, C = grid[0].length;

        // queue : all starting cells with rotten oranges
        Queue<Integer> queue = new ArrayDeque();
        Map<Integer, Integer> depth = new HashMap(); //key: 位置   value: 时间
        //初始化
        for (int r = 0; r < R; ++r)
            for (int c = 0; c < C; ++c)
                if (grid[r][c] == 2) {
                    int code = r * C + c;  //位置(index)
                    queue.add(code);
                    depth.put(code, 0);
                }

        int ans = 0;
        while (!queue.isEmpty()) {  //借助队列进行广度优先搜素
            int code = queue.remove();
            int r = code / C, c = code % C;
            for (int k = 0; k < 4; ++k) {  //遍历四个方向
                int nr = r + dr[k];
                int nc = c + dc[k];
                if (0 <= nr && nr < R && 0 <= nc && nc < C && grid[nr][nc] == 1) {
                    grid[nr][nc] = 2;
                    int ncode = nr * C + nc;
                    queue.add(ncode);
                    depth.put(ncode, depth.get(code) + 1);
                    ans = depth.get(ncode);
                }
            }
        }
        for (int[] row: grid) {
            for (int v: row) {
                if (v == 1) {
                    return -1;
                }

            }
        }
        return ans;
    }
}

March 5

1103. Divided Candy II

Sit in rows and divide the candy.

We bought some candy candies and plan to distribute them to n = num_people children in the queue.

Give 1 candy to the first child, 2 candy to the second child, and so on, until you give n candy to the last child.

Then, we return to the starting point of the team and give the first child n + 1 candy, the second child n + 2, and so on, until the last child 2 * n candy.

Repeat the above process (each time one more candy is given than the last time, and when the end of the line is reached, start from the beginning of the line again) until we have divided all the candies. Note that even if there are not enough candies left in our hands (not more than the number of candies sent last time), all of these candies will be distributed to the current children.

Return an array whose length is num_people and the sum of elements is candies to indicate the final distribution of the candies (that is, ans[i] represents the number of candies allocated by the i-th child).

示例 1:

输入:candies = 7, num_people = 4
输出:[1,2,3,1]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0,0]。
第三次,ans[2] += 3,数组变为 [1,2,3,0]。
第四次,ans[3] += 1(因为此时只剩下 1 颗糖果),最终数组变为 [1,2,3,1]。
class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        int index = 0;
        while (candies > 0) {
            for (int i = 0; i < num_people; i++) {
                int sum = index * num_people + (i + 1);
                if (candies > sum) {
                    res[i] += sum;
                    candies -= sum;
                } else {
                    res[i] += candies;
                    candies = 0;
                }
            }
            index++;
        }
        return res;
    }
}

March 6

Interview Question 57-II. The sequence of continuous positive numbers whose sum is s

Input a positive integer target, and output all consecutive positive integer sequences (containing at least two numbers) whose sum is target.

The numbers in the sequence are arranged from small to large, and different sequences are arranged from small to large according to the first number.

示例 1:

输入:target = 9
输出:[[2,3,4],[4,5]]

示例 2:

输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

        This problem can be solved by violence, but the best way is to use a sliding window

        The sliding window can be seen as a framed part of the array. In some array problems, we can use a sliding window to observe possible candidate results. When the sliding window slides from the left to the right of the array, we can find the best result from all the candidate results.

sliding-window

  • When the sum of the window is smaller than the target, the sum of the window needs to be increased, so to enlarge the window, the right edge of the window moves to the right
  • When the sum of the windows is greater than the target, the sum of the windows needs to be reduced, so to shrink the window, move the left edge of the window to the right
  • When the sum of the windows happens to be equal to the target, we need to record the results at this time. Suppose the window at this time is [i, j)[i,j), then we have found a sequence starting with ii, which is also the only sequence starting with ii. Next, we need to find the sequence starting with i+1i+1, so The left border of the window should be moved to the right
class Solution {
    public int[][] findContinuousSequence(int target) {
        int i = 1; // 滑动窗口的左边界
        int j = 1; // 滑动窗口的右边界
        int sum = 0; // 滑动窗口中数字的和
        List<int[]> res = new ArrayList<>();  //注意写法:目的是为了方便将List转换成二维数组

        while (i <= target / 2) {
            if (sum < target) {
                // 右边界向右移动
                sum += j;
                j++;
            } else if (sum > target) {
                // 左边界向右移动
                sum -= i;
                i++;
            } else {
                // 记录结果
                int[] arr = new int[j-i];
                for (int k = i; k < j; k++) {
                    arr[k-i] = k;
                }
                res.add(arr);
                // 左边界向右移动
                sum -= i;
                i++;
            }
        }

        return res.toArray(new int[res.size()][]);
    }
}

March 7

Interview Question 59-II. Maximum Queue

Please define a queue and implement the function max_value to get the maximum value in the queue. The time complexity of the functions max_value, push_back and pop_front are all O(1).

If the queue is empty, pop_front and max_value need to return -1

示例 1:

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

        This question is mainly queue + deque embodiment.

class MaxQueue {
    Queue<Integer> queue;
    Deque<Integer> maxQueue;  //双端队列(也需要存全部元素,只不过是单调递减的)
    public MaxQueue() {
        queue = new ArrayDeque();
        maxQueue = new ArrayDeque();
    }
    public int max_value() {
        return maxQueue.isEmpty() ? -1 : maxQueue.peek();
    }
    public void push_back(int value) {
        queue.add(value);
        while(!maxQueue.isEmpty() && value > maxQueue.getLast()) {
            maxQueue.pollLast();  //从尾部把小于当前value的全部删除(因为用不到了)
        }
        maxQueue.add(value);
    }
    public int pop_front() {
        if(queue.isEmpty())
            return -1;
        int ans = queue.poll();
        if(ans == maxQueue.peek()) {
            maxQueue.poll();
        } 
        return ans;
    }
}

March 8 

322. Change Exchange

Given coins of different denominations and a total amount. Write a function to calculate the minimum number of coins required to make up the total amount. If no coin combination can make up the total amount, return -1.

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

        This problem is a typical DP problem , of course, it can also be solved using DFS. 

public class Solution {
    //动态规划
    public int coinChange(int[] coins, int amount) {
        int dp[] = new int[amount + 1];
        Arrays.fill(dp, amount + 1);
        dp[0] = 0;

        //反向dp
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }

    //DFS + 剪枝
    int res = Integer.MAX_VALUE;
    public int coinChange(int[] coins, int amount) {
        Arrays.sort(coins);
        dfs(coins, coins.length - 1, amount, 0);  //用最大的面额作为初始条件
        return res == Integer.MAX_VALUE ? -1 : res;
    }
    public void dfs(int[] coins, int index, int amount, int cnt){
        if(index < 0){
            return;
        }
        for(int c = amount/coins[index]; c >= 0; c--){
            int na = amount - c * coins[index];  //剩下的面额
            int ncnt = cnt + c;  //目前使用的硬币数
            if(na == 0){  //剩余的面额为0(符合)
                res = Math.min(res, ncnt);
                break; //剪枝1
            }
            if(ncnt + 1 >= res){  //使用的硬币数过多,已无法满足最优的要求(舍弃)
                break; //剪枝2
            }
            dfs(coins, index-1, na, ncnt);
        }
    }
}

March 9

121. The best time to buy and sell stocks

Given an array, its i-th element is the price of a given stock on the i-th day.

If you are only allowed to complete at most one transaction (that is, buy and sell one stock), design an algorithm to calculate the maximum profit you can make.

Note that you cannot sell stocks before buying them.

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意:利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

         The more violent way for this question is to use a double loop. In fact, it can be improved by using a single loop. The code is as follows:

public class Solution {
    public int maxProfit(int[] prices) {
        int min = Integer.MAX_VALUE;
        int maxProfit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < min) {
                min = prices[i];
            } else if (prices[i] - min > maxProfit) {
                maxProfit = prices[i] - min;
            }
        }
        return maxProfit;
    }
}

March 10

543. Diameter of Binary Tree

Given a binary tree, you need to calculate its diameter and length. The diameter length of a binary tree is the maximum of the path lengths of any two nodes. This path may pass through the root node.

示例 :
给定二叉树

          1
         / \
        2   3
       / \     
      4   5    

Screenshot 2020-03-10 00.36.38.png

        There is a pitfall in this question. . Note: The maximum value does not necessarily include the root node . But it must pass through a certain node and DFS can be used .

class Solution {
    int res = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        dfs(root);
        return res;
    }

    // 函数dfs的作用:找到以root为根节点的二叉树的最大深度
    private int dfs(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftDepth = dfs(root.left);
        int rightDepth = dfs(root.right);
        res = Math.max(res, leftDepth + rightDepth);
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

 

March 14

300. Longest Ascending Subsequence

Given an unordered integer array, find the length of the longest ascending subsequence.

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
public class Solution {
    //动态规划法
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        //dp[j]代表nums [0…j] 中以 nums[j] 结尾的最长上升子序列的长度
        dp[0] = 1;
        int maxans = 1;
        for (int i = 1; i < dp.length; i++) {
            int maxval = 0;
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    maxval = Math.max(maxval, dp[j]);
                }
            }
            dp[i] = maxval + 1;
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }

    //贪心 + 二分查找
    public int lengthOfLIS1(int[] nums) {
        /**
         由定义知dp数组必然是一个递增数组, 可以用 maxL 来表示最长递增子序列的长度.
         对数组进行迭代, 依次判断每个数num将其插入dp数组相应的位置:
         1. num > dp[maxL], 表示num比所有已知递增序列的尾数都大, 将num添加入dp
         数组尾部, 并将最长递增序列长度maxL加1
         2. dp[i-1] < num <= dp[i], 只更新相应的dp[i]
         **/
        int maxL = 0;  //最长递增子序列的长度
        int[] dp = new int[nums.length];
        //dp[i]: 所有长度为i+1的递增子序列中, 最小的那个序列尾数
        for(int num : nums) {
            // 二分法查找, 也可以调用库函数如binary_search
            int lo = 0, hi = maxL;
            while(lo < hi) {
                int mid = lo + (hi - lo) / 2;
                if(dp[mid] < num) {
                    lo = mid+1;
                } else {
                    hi = mid;
                }
            }
            dp[lo] = num;
            if(lo == maxL) {
                maxL++;
            }
        }
        return maxL;
    }
}

Continuously updating...

Guess you like

Origin blog.csdn.net/qq_34519487/article/details/104642141