stack 相关 341, 32, 636

341. Flatten Nested List Iterator
Medium

You are given a nested list of integers nestedList. Each element is either an integer or a list whose elements may also be integers or other lists. Implement an iterator to flatten it.

Implement the NestedIterator class:

  • NestedIterator(List<NestedInteger> nestedList) Initializes the iterator with the nested list nestedList.
  • int next() Returns the next integer in the nested list.
  • boolean hasNext() Returns true if there are still some integers in the nested list and false otherwise.

Your code will be tested with the following pseudocode:

initialize iterator with nestedList
res = []
while iterator.hasNext()
    append iterator.next() to the end of res
return res

If res matches the expected flattened list, then your code will be judged as correct.

Example 1:

Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].

Example 2:

Input: nestedList = [1,[4,[6]]]
Output: [1,4,6]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6].

 Constraints:

  • 1 <= nestedList.length <= 500
  • The values of the integers in the nested list is in the range [-106, 106].
/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * public interface NestedInteger {
 *
 *     // @return true if this NestedInteger holds a single integer, rather than a nested list.
 *     public boolean isInteger();
 *
 *     // @return the single integer that this NestedInteger holds, if it holds a single integer
 *     // Return null if this NestedInteger holds a nested list
 *     public Integer getInteger();
 *
 *     // @return the nested list that this NestedInteger holds, if it holds a nested list
 *     // Return empty list if this NestedInteger holds a single integer
 *     public List<NestedInteger> getList();
 * }
 */
public class NestedIterator implements Iterator<Integer> {
    Stack<NestedInteger> stack;
    public NestedIterator(List<NestedInteger> nestedList) {
        stack = new Stack();
        fill(nestedList,stack);
    }
    @Override
    public Integer next() {
        if(!hasNext()) return -1;
        Integer curr = stack.pop().getInteger();
        return curr;
    }
    @Override
    public boolean hasNext() {
        while(!stack.isEmpty() && !stack.peek().isInteger() ) {
            fill(stack.pop().getList(),stack);
        }
        return !stack.isEmpty();
    }
    private void fill(List<NestedInteger> nestedList,Stack<NestedInteger> stack){
        for(int i=nestedList.size()-1;i>=0;i--){
            stack.push(nestedList.get(i));
        }
    }
}

 

1209. Remove All Adjacent Duplicates in String II
Medium

You are given a string s and an integer k, a k duplicate removal consists of choosing k adjacent and equal letters from s and removing them, causing the left and the right side of the deleted substring to concatenate together.

We repeatedly make k duplicate removals on s until we no longer can.

Return the final string after all such duplicate removals have been made. It is guaranteed that the answer is unique.

 Example 1:

Input: s = "abcd", k = 2
Output: "abcd"
Explanation: There's nothing to delete.

Example 2:

Input: s = "deeedbbcccbdaa", k = 3
Output: "aa"
Explanation: 
First delete "eee" and "ccc", get "ddbbbdaa"
Then delete "bbb", get "dddaa"
Finally delete "ddd", get "aa"

Example 3:

Input: s = "pbbcggttciiippooaais", k = 2
Output: "ps"

 Constraints:

  • 1 <= s.length <= 105
  • 2 <= k <= 104
  • s only contains lower case English letters.
class Solution {
    public String removeDuplicates(String s, int k) {
        Stack<Node> stack = new Stack();
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(stack.isEmpty() || stack.peek().val != c) stack.push(new Node(c,1));
            else if(stack.peek().val == c){
                if(stack.peek().count == k-1) stack.pop();
                else stack.peek().count++;
            }
        }
        StringBuffer result = new StringBuffer();
        for(Node node:stack){
            for(int i=0;i<node.count;i++){
                result.append(node.val);
            }
        }
        return result.toString();
    }
    
}
class Node{
    char val;
    int count;
    Node(char val, int count){
        this.val = val;
        this.count = count;
    }
}

 

Given a string containing just the characters '(' and ')', return the length of the longest valid (well-formed) parentheses 

substring

Example 1:

Input: s = "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()".

Example 2:

Input: s = ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()".

Example 3:

Input: s = ""
Output: 0

Constraints:

  • 0 <= s.length <= 3 * 104
  • s[i] is '(', or ')'.
class Solution {
    public int longestValidParentheses(String s) {
        Stack<Integer> stack = new Stack<>();
        int result = 0;
        stack.push(-1); //why 可以handle这种情况 ()(()
        char[] arr = s.toCharArray();
        for(int i = 0; i < s.length(); i++) {
            if(arr[i] == '(') {
                stack.push(i);
            }
            else {
                // 如果是( ,那么pop
                if(!stack.isEmpty() && stack.peek() != -1 && arr[stack.peek()] == '(') {
                    // pop (
                    stack.pop();
                    // 计算当前合法长度
                    result = Math.max(result, i - stack.peek());
                }
                // 没有匹配的左括弧,那么直接入栈
                else {
                    stack.push(i);
                }
            }
        }
        return result;
    }
}

 

class Solution {
    public int longestValidParentheses(String s) {
        int left = 0, right = 0;
        int result = 0;
        for(int i = 0; i < s.length(); i++) {
            if(s.charAt(i) == '(') left++; 
            else right++;
            if(left == right) result = Math.max(result, right + left);
            // 不再合法,从头开始计算
            else if(left < right){
                left = 0;
                right = 0;
            }
        }
        left = 0;
        right = 0;
        for(int i = s.length() - 1; i >= 0; i--) {
            if(s.charAt(i) == '(') left++; else right++;
            if(left == right) result = Math.max(result, right + left);
            // 不再合法,从头开始计算
            else if(left > right){
                left = 0;
                right = 0;
            }
        }
        return result;
    }
}

 

On a single-threaded CPU, we execute a program containing n functions. Each function has a unique ID between 0 and n-1.

Function calls are stored in a call stack: when a function call starts, its ID is pushed onto the stack, and when a function call ends, its ID is popped off the stack. The function whose ID is at the top of the stack is the current function being executed. Each time a function starts or ends, we write a log with the ID, whether it started or ended, and the timestamp.

You are given a list logs, where logs[i] represents the ith log message formatted as a string "{function_id}:{"start" | "end"}:{timestamp}". For example, "0:start:3" means a function call with function ID 0 started at the beginning of timestamp 3, and "1:end:2" means a function call with function ID 1 ended at the end of timestamp 2. Note that a function can be called multiple times, possibly recursively.

A function's exclusive time is the sum of execution times for all function calls in the program. For example, if a function is called twice, one call executing for 2 time units and another call executing for 1 time unit, the exclusive time is 2 + 1 = 3.

Return the exclusive time of each function in an array, where the value at the ith index represents the exclusive time for the function with ID i.

 

Example 1:

Input: n = 2, logs = ["0:start:0","1:start:2","1:end:5","0:end:6"]
Output: [3,4]
Explanation:
Function 0 starts at the beginning of time 0, then it executes 2 for units of time and reaches the end of time 1.
Function 1 starts at the beginning of time 2, executes for 4 units of time, and ends at the end of time 5.
Function 0 resumes execution at the beginning of time 6 and executes for 1 unit of time.
So function 0 spends 2 + 1 = 3 units of total time executing, and function 1 spends 4 units of total time executing.

Example 2:

Input: n = 1, logs = ["0:start:0","0:start:2","0:end:5","0:start:6","0:end:6","0:end:7"]
Output: [8]
Explanation:
Function 0 starts at the beginning of time 0, executes for 2 units of time, and recursively calls itself.
Function 0 (recursive call) starts at the beginning of time 2 and executes for 4 units of time.
Function 0 (initial call) resumes execution then immediately calls itself again.
Function 0 (2nd recursive call) starts at the beginning of time 6 and executes for 1 unit of time.
Function 0 (initial call) resumes execution at the beginning of time 7 and executes for 1 unit of time.
So function 0 spends 2 + 4 + 1 + 1 = 8 units of total time executing.

Example 3:

Input: n = 2, logs = ["0:start:0","0:start:2","0:end:5","1:start:6","1:end:6","0:end:7"]
Output: [7,1]
Explanation:
Function 0 starts at the beginning of time 0, executes for 2 units of time, and recursively calls itself.
Function 0 (recursive call) starts at the beginning of time 2 and executes for 4 units of time.
Function 0 (initial call) resumes execution then immediately calls function 1.
Function 1 starts at the beginning of time 6, executes 1 unit of time, and ends at the end of time 6.
Function 0 resumes execution at the beginning of time 6 and executes for 2 units of time.
So function 0 spends 2 + 4 + 1 = 7 units of total time executing, and function 1 spends 1 unit of total time executing.

Constraints:

  • 1 <= n <= 100
  • 1 <= logs.length <= 500
  • 0 <= function_id < n
  • 0 <= timestamp <= 109
  • No two start events will happen at the same timestamp.
  • No two end events will happen at the same timestamp.
  • Each function has an "end" log for each "start" log.
class Solution {
    /**
    思路: 使用stack去track函数日志调用过程
        调用结束时:
            1.更新函数调用的时间
            2.更新父函数的other(调用子函数)时间
            3.exclusive = cost - other
            4.使用int[] 累加每个函数的调用exclusive cost
     */
    public int[] exclusiveTime(int n, List<String> logs) {
        int[] result = new int[n];
        Stack<Function> stack = new Stack<>();
        for(String log : logs) {
            String[] arr = log.split(":");
            // 进程信息
            int num = Integer.parseInt(arr[0]);
            // 时间戳
            int time = Integer.parseInt(arr[2]);
            // start/end
            String type = arr[1];
            // 如果是调用开始,入栈
            if(type.equals("start")) {
                stack.push(new Function(num, time));
            }
            else {
            //否则是调用结束
                Function curr = stack.pop();
                // 计算当前函数总cost
                curr.cost = time - curr.start + 1;
                // 将exclusive cost 更新到 map
                result[curr.num] += curr.cost - curr.other;
                // 如果不是最外层函数,那么要将函数调用时间更新到父函数
                if(!stack.isEmpty()) {
                    // 获取父函数
                    Function parent = stack.peek();
                    // 将当前函数cost 更新到父函数的other
                    parent.other += curr.cost;
                }
                // System.out.println(curr.num + ":" + curr.cost + ":" + curr.other);
            }
        }
        return result;
    }
}
class Function{
    int num;
    int start; 
    int cost;
    int other;
    Function(int num, int start) {
        this.num = num;
        this.start = start;
        cost = 0;
    }
}

 

posted @ 2022-02-20 23:28  xiaoyongyong  阅读(35)  评论(0)    收藏  举报