2023-04-16 算法面试中常见的栈和队列问题

news2024/12/26 13:00:19

栈和队列

1 栈的基础应用:20.括号匹配

class Solution {
     public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '[' || c == '{') {
                stack.push(c);
            } else {
                // 还有字符串但是栈已经为空了,肯定是非法表达式
                if (stack.size()==0){
                    return false;
                }
                char cPop = stack.pop();
                if(cPop == '('){
                    if (c !=')'){
                        return false;
                    }
                }else if (cPop == '['){
                    if (c != ']'){
                        return false;
                    }
                }else if (cPop== '{'){
                    if (c != '}'){
                        return false;
                    }
                }
            }
        }
        if (stack.size() != 0) {
            return false;
        }
        return true;
    }
}

本节类似问题:150、71

150.逆波兰表达式求值

71.简化路径

##2 栈和递归的关系,以二叉树的前、中、后序遍历为例(图的深度优先遍历DFS原理是一样的)

参考Part2Basic/第06章_二分搜索树BST.md的6.6和6.7

144.二叉树前序遍历

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        preorder(root, list);
        return list;
    }

    /// 遍历以node作为根节点的子树
    private void preorder(TreeNode node, List<Integer> list){
        // 1.递归终止条件
        if(node == null){
            return;
        }
        // 2.递归具体逻辑
        list.add(node.val);
        preorder(node.left, list);
        preorder(node.right, list);
    }
}

94.二叉树中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inorder(root, list);
        return list;
    }

    /// 遍历以node作为根节点的子树
    private void inorder(TreeNode node, List<Integer> list){
        // 1.递归终止条件
        if(node == null){
            return;
        }
        // 2.递归具体逻辑
        inorder(node.left, list);
        list.add(node.val);
        inorder(node.right, list);
    }
}

145.二叉树后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        postorder(root, list);
        return list;
    }

    /// 遍历以node作为根节点的子树
    private void postorder(TreeNode node, List<Integer> list){
        // 1.递归终止条件
        if(node == null){
            return;
        }
        // 2.递归具体逻辑
        postorder(node.left, list);
        postorder(node.right, list);
        list.add(node.val);
    }
}

589.n叉树前序遍历

class Solution {
    public List<Integer> preorder(Node root) {
        List<Integer> list = new ArrayList<>();
        preorder(root, list);
        return list;
    }

    private void preorder(Node node, List<Integer> list){
        // 1.递归终止条件
        if(node == null){
            return;
        }

        // 2.递归具体逻辑
        list.add(node.val);
        for(Node child : node.children){
            preorder(child, list);
        }
    }
}

590.n叉树后序遍历

class Solution {
    public List<Integer> postorder(Node root) {
        List<Integer> list = new ArrayList<>();
        postorder(root, list);
        return list;
    }

    private void postorder(Node node, List<Integer> list){
        // 1.递归终止条件
        if(node == null){
            return;
        }

        // 2.递归具体逻辑
        for(Node child : node.children){
            postorder(child, list);
        }
        list.add(node.val);
    }
}

##3 使用栈模拟递归

递归实际是一种系统栈调用

341.扁平化嵌套列表迭代器

/**
 * // 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 null if this NestedInteger holds a single integer
 *     public List<NestedInteger> getList();
 * }
 */
public class NestedIterator implements Iterator<Integer> {
    // 定义一个队列
    private Queue<Integer> queue = new ArrayDeque<>();
    // 根据文件头各个函数的注释进行合理的递归调用
    private void init(List<NestedInteger> nestedList){
        for(NestedInteger nestedInteger : nestedList){
            if(nestedInteger.isInteger()){
                queue.add(nestedInteger.getInteger());
            }else {
                init(nestedInteger.getList());
            }
        }
    }
    public NestedIterator(List<NestedInteger> nestedList) {
        init(nestedList);
    }

    @Override
    public Integer next() {
        return queue.remove();
    }

    @Override
    public boolean hasNext() {
        return !queue.isEmpty();
    }
}

/**
 * Your NestedIterator object will be instantiated and called as such:
 * NestedIterator i = new NestedIterator(nestedList);
 * while (i.hasNext()) v[f()] = i.next();
 */

##4 队列的典型应用:二叉树的层序遍历以及图的BFS

102.二叉树的层序遍历

可以记住第几层的BFS

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null){
            return list;
        }
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            // 一次性把当前层的节点全部弹出
            List<Integer> levelList = new ArrayList<>();
            while(size-- > 0){
                TreeNode node = queue.remove();
                levelList.add(node.val);
                if(node.left != null){
                    queue.add(node.left);
                }
                if(node.right != null){
                    queue.add(node.right);
                }
            }
            list.add(levelList);
        }
        return list;
    }
}

不用记住第几层的BFS

class Solution {
    public List<Integer> levelOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            // 一次性把当前层的节点全部弹出
            TreeNode node = queue.remove();
            list.add(node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        return list;
    }
}

此外还有107、103、199

107.二叉树的层次遍历 II

相比102实际就加了Collections.reverse(list);这一行


class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null){
            return list;
        }
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            // 一次性把当前层的节点全部弹出
            List<Integer> levelList = new ArrayList<>();
            while(size-- > 0){
                TreeNode node = queue.remove();
                levelList.add(node.val);
                if(node.left != null){
                    queue.add(node.left);
                }
                if(node.right != null){
                    queue.add(node.right);
                }
            }
            list.add(levelList);
        }
        // 相比102就加了下面一行
        Collections.reverse(list);
        return list;
    }
}

103.二叉树的锯齿形层次遍历

相比102实际只加了下面几行,用于偶数行逆序

for (int i = 0; i < list.size(); i++) {
    List<Integer> listCur = list.get(i);
    if (i % 2 == 1) {
        Collections.reverse(listCur);
    }
}
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            // 一次性把当前层的节点全部弹出
            List<Integer> levelList = new ArrayList<>();
            while (size-- > 0) {
                TreeNode node = queue.remove();
                levelList.add(node.val);
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            list.add(levelList);
        }
        for (int i = 0; i < list.size(); i++) {
            List<Integer> listCur = list.get(i);
            if (i % 2 == 1) {
                Collections.reverse(listCur);
            }
        }
        return list;
    }
}

199.二叉树的右视图

当到达本层最后一个元素时才加到list中

核心代码:

 // 核心,到达本行最后一个元素才加到list里
if (i == size - 1) {
    list.add(node.val);
}

完整实现如下:

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            int i = 0;
            while (i < size) {
                TreeNode node = queue.remove();
                // 核心,到达本行最后一个元素才加到list里
                if (i == size - 1) {
                    list.add(node.val);
                }
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
                i++;
            }
        }
        return list;
    }
}

##5 BFS和图的最短路径:279.完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.
示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.

思路:

  • 对问题建模,整个问题转化为一个图论问题。
  • 从n到0,每个数组表示一个节点
  • 如果两个数字x到y相差一个完全平方数,则连接一条边,我们得到了一个有向无权图。
  • 原问题转换为:求这个无权图从n到0的最短路径,求最短路径一般都用BFS
    完全平方数的图论思路
public class Solution {
    private class Node {
        /**
         * 节点编号
         */
        int num;
        /**
         * 节点到起点的距离
         */
        int distance;

        public Node(int num, int distance) {
            this.num = num;
            this.distance = distance;
        }
    }

    public int numSquares(int n) {
        // 这里用map表达图中的一个节点,键代表节点,值代表距离起点的距离(无权图可以认为是经过的节点个数)
        Queue<Node> queue = new ArrayDeque<>();
        queue.add(new Node(n, 0));
        boolean[] visited = new boolean[n];
        while (!queue.isEmpty()) {
            Node node = queue.remove();
            if (node.num == 0) {
                // 这里我们只用到了距离,不需要具体的路径,需要完整路径地话还需要pre数组
                return node.distance;
            }
            // 遍历邻接点,把他们加入到队列中
            for (int i = 1; node.num - i * i >= 0; i++) {
                if (!visited[node.num - i * i]) {
                    queue.add(new Node(node.num - i * i, node.distance + 1));
                    visited[node.num - i * i] = true;
                }
            }
        }
        return 0;
    }
}

类似问题:127、126

使用BFS关键是要找到邻接点

127.单词接龙

class Solution {
    private class Node {
        /**
         * 节点对应的单词
         */
        String word;
        /**
         * 当前单词到起点单词的距离
         */
        int distance;

        public Node(String word, int distance) {
            this.word = word;
            this.distance = distance;
        }
    }

    /**
     * 判断两个单词是否只有一个单词不同
     * 两个单词的长度是相等地
     */
    private boolean oneCharDiff(String wordA, String wordB) {
        // 不同字符的个数
        int diffCnt = 0;
        for (int i = 0; i < wordA.length(); i++) {
            if (wordA.charAt(i) != wordB.charAt(i)) {
                diffCnt++;
            }
        }
        return diffCnt == 1;
    }

    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        // 访问数组
        Map<String, Boolean> visited = new HashMap<>();
        Queue<Node> queue = new ArrayDeque<>();
        queue.add(new Node(beginWord, 1));
        visited.put(beginWord, true);
        while (!queue.isEmpty()) {
            Node node = queue.remove();
            for (String word : wordList) {
                if (oneCharDiff(word, node.word) && visited.get(word) == null) {
                    // 一旦找到目标单词endWord,直接返回
                    if (word.equals(endWord)) {
                        return node.distance + 1;
                    }
                    // 和父节点相比只有一个节点不同而且还没被访问
                    queue.add(new Node(word, node.distance + 1));
                    visited.put(word, true);
                }
            }
        }
        return 0;
    }
}

126.单词接龙2之记住所有可达路径,参考博客

第1个。超时的版本,21/39

class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        List<List<String>> ans = new ArrayList<>();
        // 如果不含有结束单词,直接结束,不然后边会造成死循环
        if (!wordList.contains(endWord)) {
            return ans;
        }
        // 利用 BFS 得到所有的邻居节点,以及每个节点的所在层数
        HashMap<String, Integer> mapWordDistance = new HashMap<>();
        HashMap<String, ArrayList<String>> map = new HashMap<>();
        bfs(beginWord, endWord, wordList, map, mapWordDistance);
        ArrayList<String> path = new ArrayList<>();
        // temp 用来保存当前的路径
        path.add(beginWord);
        dfs(beginWord, endWord, map, mapWordDistance, path, ans);
        return ans;
    }

    private void dfs(String beginWord, String endWord, HashMap<String, ArrayList<String>> map,
                                   HashMap<String, Integer> mapWordDistance, List<String> path, List<List<String>> pathList) {
        if (beginWord.equals(endWord)) {
            pathList.add(new ArrayList<>(path));
            return;
        }
        ArrayList<String> neighbors = map.getOrDefault(beginWord, new ArrayList<String>());
        for (String neighbor : neighbors) {
            //判断层数是否符合
            if (mapWordDistance.get(beginWord) + 1 == mapWordDistance.get(neighbor)) {
                path.add(neighbor);
                dfs(neighbor, endWord, map, mapWordDistance, path, pathList);
                path.remove(path.size() - 1);
            }
        }
    }

    public void bfs(String beginWord, String endWord, List<String> wordList, HashMap<String, ArrayList<String>> map, HashMap<String, Integer> distance) {
        Queue<String> queue = new ArrayDeque<>();
        queue.offer(beginWord);
        distance.put(beginWord, 0);
        boolean isFound = false;
        int depth = 0;
        Set<String> dict = new HashSet<>(wordList);
        while (!queue.isEmpty()) {
            int size = queue.size();
            depth++;
            for (int j = 0; j < size; j++) {
                String temp = queue.poll();
                // 一次性得到所有的下一个的节点
                ArrayList<String> neighbors = getOneCharDiffWords(temp, dict);
                map.put(temp, neighbors);
                for (String neighbor : neighbors) {
                    if (!distance.containsKey(neighbor)) {
                        distance.put(neighbor, depth);
                        if (neighbor.equals(endWord)) {
                            isFound = true;
                        }
                        queue.offer(neighbor);
                    }

                }
            }
            if (isFound) {
                break;
            }
        }
    }

    private ArrayList<String> getOneCharDiffWords(String node, Set<String> dict) {
        ArrayList<String> res = new ArrayList<>();
        char chs[] = node.toCharArray();
        for (char ch = 'a'; ch <= 'z'; ch++) {
            for (int i = 0; i < chs.length; i++) {
                if (chs[i] == ch) {
                    continue;
                }
                char old_ch = chs[i];
                chs[i] = ch;
                if (dict.contains(String.valueOf(chs))) {
                    res.add(String.valueOf(chs));
                }
                chs[i] = old_ch;
            }

        }
        return res;
    }

    /**
     * String beginWord = "hit";
     * String endWord = "cog";
     * String[] words = {"hot","dot","dog","lot","log", "cog"};
     * <p>
     * String beginWord = "qa";
     * String endWord = "sq";
     * String[] words = {"si", "go", "se", "cm", "so", "ph", "mt", "db", "mb", "sb", "kr", "ln", "tm", "le", "av", "sm", "ar", "ci", "ca", "br", "ti", "ba", "to", "ra", "fa", "yo", "ow", "sn", "ya", "cr", "po", "fe", "ho", "ma", "re", "or", "rn", "au", "ur", "rh", "sr", "tc", "lt", "lo", "as", "fr", "nb", "yb", "if", "pb", "ge", "th", "pm", "rb", "sh", "co", "ga", "li", "ha", "hz", "no", "bi", "di", "hi", "qa", "pi", "os", "uh", "wm", "an", "me", "mo", "na", "la", "st", "er", "sc", "ne", "mn", "mi", "am", "ex", "pt", "io", "be", "fm", "ta", "tb", "ni", "mr", "pa", "he", "lr", "sq", "ye"};
     * <p>
     * String beginWord = "cet";
     * String endWord = "ism";
     * String[] words = {"kid", "tag", "pup", "ail", "tun", "woo", "erg", "luz", "brr", "gay", "sip", "kay", "per", "val", "mes", "ohs", "now", "boa", "cet", "pal", "bar", "die", "war", "hay", "eco", "pub", "lob", "rue", "fry", "lit", "rex", "jan", "cot", "bid", "ali", "pay", "col", "gum", "ger", "row", "won", "dan", "rum", "fad", "tut", "sag", "yip", "sui", "ark", "has", "zip", "fez", "own", "ump", "dis", "ads", "max", "jaw", "out", "btu", "ana", "gap", "cry", "led", "abe", "box", "ore", "pig", "fie", "toy", "fat", "cal", "lie", "noh", "sew", "ono", "tam", "flu", "mgm", "ply", "awe", "pry", "tit", "tie", "yet", "too", "tax", "jim", "san", "pan", "map", "ski", "ova", "wed", "non", "wac", "nut", "why", "bye", "lye", "oct", "old", "fin", "feb", "chi", "sap", "owl", "log", "tod", "dot", "bow", "fob", "for", "joe", "ivy", "fan", "age", "fax", "hip", "jib", "mel", "hus", "sob", "ifs", "tab", "ara", "dab", "jag", "jar", "arm", "lot", "tom", "sax", "tex", "yum", "pei", "wen", "wry", "ire", "irk", "far", "mew", "wit", "doe", "gas", "rte", "ian", "pot", "ask", "wag", "hag", "amy", "nag", "ron", "soy", "gin", "don", "tug", "fay", "vic", "boo", "nam", "ave", "buy", "sop", "but", "orb", "fen", "paw", "his", "sub", "bob", "yea", "oft", "inn", "rod", "yam", "pew", "web", "hod", "hun", "gyp", "wei", "wis", "rob", "gad", "pie", "mon", "dog", "bib", "rub", "ere", "dig", "era", "cat", "fox", "bee", "mod", "day", "apr", "vie", "nev", "jam", "pam", "new", "aye", "ani", "and", "ibm", "yap", "can", "pyx", "tar", "kin", "fog", "hum", "pip", "cup", "dye", "lyx", "jog", "nun", "par", "wan", "fey", "bus", "oak", "bad", "ats", "set", "qom", "vat", "eat", "pus", "rev", "axe", "ion", "six", "ila", "lao", "mom", "mas", "pro", "few", "opt", "poe", "art", "ash", "oar", "cap", "lop", "may", "shy", "rid", "bat", "sum", "rim", "fee", "bmw", "sky", "maj", "hue", "thy", "ava", "rap", "den", "fla", "auk", "cox", "ibo", "hey", "saw", "vim", "sec", "ltd", "you", "its", "tat", "dew", "eva", "tog", "ram", "let", "see", "zit", "maw", "nix", "ate", "gig", "rep", "owe", "ind", "hog", "eve", "sam", "zoo", "any", "dow", "cod", "bed", "vet", "ham", "sis", "hex", "via", "fir", "nod", "mao", "aug", "mum", "hoe", "bah", "hal", "keg", "hew", "zed", "tow", "gog", "ass", "dem", "who", "bet", "gos", "son", "ear", "spy", "kit", "boy", "due", "sen", "oaf", "mix", "hep", "fur", "ada", "bin", "nil", "mia", "ewe", "hit", "fix", "sad", "rib", "eye", "hop", "haw", "wax", "mid", "tad", "ken", "wad", "rye", "pap", "bog", "gut", "ito", "woe", "our", "ado", "sin", "mad", "ray", "hon", "roy", "dip", "hen", "iva", "lug", "asp", "hui", "yak", "bay", "poi", "yep", "bun", "try", "lad", "elm", "nat", "wyo", "gym", "dug", "toe", "dee", "wig", "sly", "rip", "geo", "cog", "pas", "zen", "odd", "nan", "lay", "pod", "fit", "hem", "joy", "bum", "rio", "yon", "dec", "leg", "put", "sue", "dim", "pet", "yaw", "nub", "bit", "bur", "sid", "sun", "oil", "red", "doc", "moe", "caw", "eel", "dix", "cub", "end", "gem", "off", "yew", "hug", "pop", "tub", "sgt", "lid", "pun", "ton", "sol", "din", "yup", "jab", "pea", "bug", "gag", "mil", "jig", "hub", "low", "did", "tin", "get", "gte", "sox", "lei", "mig", "fig", "lon", "use", "ban", "flo", "nov", "jut", "bag", "mir", "sty", "lap", "two", "ins", "con", "ant", "net", "tux", "ode", "stu", "mug", "cad", "nap", "gun", "fop", "tot", "sow", "sal", "sic", "ted", "wot", "del", "imp", "cob", "way", "ann", "tan", "mci", "job", "wet", "ism", "err", "him", "all", "pad", "hah", "hie", "aim", "ike", "jed", "ego", "mac", "baa", "min", "com", "ill", "was", "cab", "ago", "ina", "big", "ilk", "gal", "tap", "duh", "ola", "ran", "lab", "top", "gob", "hot", "ora", "tia", "kip", "han", "met", "hut", "she", "sac", "fed", "goo", "tee", "ell", "not", "act", "gil", "rut", "ala", "ape", "rig", "cid", "god", "duo", "lin", "aid", "gel", "awl", "lag", "elf", "liz", "ref", "aha", "fib", "oho", "tho", "her", "nor", "ace", "adz", "fun", "ned", "coo", "win", "tao", "coy", "van", "man", "pit", "guy", "foe", "hid", "mai", "sup", "jay", "hob", "mow", "jot", "are", "pol", "arc", "lax", "aft", "alb", "len", "air", "pug", "pox", "vow", "got", "meg", "zoe", "amp", "ale", "bud", "gee", "pin", "dun", "pat", "ten", "mob"};
     */
    public static void main(String[] args) {
        String beginWord = "hit";
        String endWord = "cog";
        String[] words = {"hot", "dot", "dog", "lot", "log", "cog"};
        List<String> wordList = new ArrayList<>(Arrays.asList(words));
        List<List<String>> ladders = new Solution().findLadders(beginWord, endWord, wordList);
        System.out.println(ladders);
    }
}

##6~7 优先队列

Java默认的java.util.PriorityQueue是基于最小堆实现地

347.前K个高频元素

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        // 元素和出现频次的映射Map
        Map<Integer, Integer> mapNumFreq = new HashMap<>();
        for (int num : nums) {
            // 更新map里面的值
            if (mapNumFreq.get(num) == null) {
                mapNumFreq.put(num, 1);
            } else {
                mapNumFreq.put(num, mapNumFreq.get(num) + 1);
            }
        }
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer key1, Integer key2) {
                // 自定义比较器,找出现频次较高地需要每次弹出最小值
                return mapNumFreq.get(key1) - mapNumFreq.get(key2);
            }
        });
        for (Integer key : mapNumFreq.keySet()) {
            if (pq.size() == k) {
                // 满了需要和栈顶元素比较,比栈顶元素大就加入到队列中
                if (mapNumFreq.get(key) > mapNumFreq.get(pq.peek())) {
                    pq.poll();
                    pq.add(key);
                }
            } else {
                // 优先队列没满就直接加入
                pq.add(key);
            }

        }
        List<Integer> result = new ArrayList<>();
        while (!pq.isEmpty()) {
            result.add(pq.poll());
        }
        // 从高频到低频
        Collections.reverse(result);
        return result;
    }
}

23.合并K个排序链表

/***********************************************************
 * @Description : 合并K个排序链表
 * @author      : 梁山广(Liang Shan Guang)
 * @date        : 2020/1/20 16:01
 * @email       : liangshanguang2@gmail.com
 ***********************************************************/
import Chapter05LinkedList.ListNode;

import java.util.PriorityQueue;

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode dummyHead = new ListNode(0);
        ListNode cur = dummyHead;
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (ListNode list : lists) {
            cur = list;
            while (cur!=null){
                pq.add(cur.val);
                cur = cur.next;
            }
        }
        cur = dummyHead;
        while (!pq.isEmpty()){
            cur.next = new ListNode(pq.remove());
            cur = cur.next;
        }
        return dummyHead.next;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/431342.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】进程间通信 -- 命名管道

前言 在管道的通信中&#xff0c;除了匿名管道&#xff0c;还有一个命名管道。 匿名管道只支持具有“亲戚关系”的进程间通信&#xff0c;而命名管道就可以支持不同的&#xff0c;任意的进程通信。 那就下来就开始我们今天的学习。 文章目录 前言一. 命名管道二. 命名管道的应用…

快速了解数据仓库建模

快速了解数据仓库建模 1、什么是OLTP和OLAP&#xff1f;2、为什么不在业务系统做数据分析呢&#xff1f;3、什么是数据库建模&#xff1f;4、关系建模。5、维度建模。5.1 事实表5.2 维度表 6、 数据仓库分层。6.1、 数仓分层结构6.2、 为什么需要对数据仓库分层&#xff1f; 1、…

Linux网络服务之DHCP篇

目录一、了解DHCP服务1.1DHCP定义1.2DHCP好处1.3DHCP的分配方式二、DHCP工作过程三. 使用DHCP动态配置主机地址一、了解DHCP服务 1.1DHCP定义 DHCP&#xff08;动态主机配置协议&#xff09;是一个局域网的网络协议。指的是由服务器控制一段IP地址范围&#xff0c;客户机登录…

基于SDM450 兼容st7701s不同id屏幕

authordaisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 sdm450 P326 在高通的 SDM450 中&#xff0c;有两种屏幕初始化代码&#xff0c;分别称为 "lk" 和 "kernel" 代码&#xff0c; "lk" 代码是用于在内核中初始化屏幕的代码。它通常在内核…

【Linux】进程间通信 -- 匿名管道的应用

前言 上篇博客初步学习了匿名管道的周边知识和使用&#xff0c;本篇文章将基于这些知识&#xff0c;实现一下进程间通信 话不多说&#xff0c;马上开始今天的内容 文章目录 前言一. 大体框架二. 分配任务三. 创建控制模块四. 开始通信五. 关闭程序六. 完整代码结束语 一. 大体框…

每日一题 leetcode1026 2023-4-18

1026. 节点与其祖先之间的最大差值 力扣题目链接 给定二叉树的根节点 root&#xff0c;找出存在于 不同 节点 A 和 B 之间的最大值 V&#xff0c;其中 V |A.val - B.val|&#xff0c;且 A 是 B 的祖先。 &#xff08;如果 A 的任何子节点之一为 B&#xff0c;或者 A 的任何…

【CSS】使用 z-index 属性值控制定位盒子的堆叠顺序 ( 多个盒子堆叠次序问题 | z-index 属性值简介 | 控制盒子堆叠次序 )

文章目录一、多个盒子堆叠次序问题二、z-index 属性值简介三、控制盒子堆叠次序一、多个盒子堆叠次序问题 在 网页布局 中 , 如果 多个盒子都设置 绝对定位 , 那么这些盒子会堆叠在一起 ; 设置了定位样式的盒子会压住标准流盒子 , 如果有多个设置定位的盒子 , 后面的盒子会压住…

数组篇刷题总结

二分查找&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target …

【brtc】视频下行弱网对抗优化

百度云 音视频实时通信五个部分 1 RTC基础 需要云端服务器参与大量边缘服务器参与采集、前处理(图像处理)、压缩编码音频 3 A 回声消除、增益健全的六大指标 </

nodejs扫描文件夹搜索包含关键词文件,可灵活配置

代码放在在末尾 文件说明&#xff1a; 关键代码&#xff1a;search.js 搜索结果&#xff1a;searchResult.txt 搜索日志&#xff1a;search.log 注&#xff1a;只保留一次的&#xff0c;需要多次自行修改logFile配置即可&#xff1b; 使用方式&#xff1a; 将代码放到需要…

c/c++:一维数组,初始化数组,循环打印数组,计算数组存储空间,数组元素个数,数组逆序算法

c/c:一维数组&#xff0c;初始化数组&#xff0c;循环打印数组&#xff0c;计算数组存储空间&#xff0c;数组元素个数&#xff0c;数组逆序算法 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; …

一文讲解系统性能分析之|iowait是什么?

我们对系统性能进行优化时&#xff0c;一般会使用 top 命令来查看系统负载和系统中各个进程的运行情况&#xff0c;从而找出影响系统性能的因素。如下图所示&#xff1a; top top 命令会输出很多系统相关的信息&#xff0c;如&#xff1a;系统负载、系统中的进程数、CPU使用率…

联诚发携多款创新产品及解决方案惊艳亮相ISLE 2023展!

这里写自定义目录标题4月7日-9日&#xff0c;ISLE 2023国际智慧显示及系统集成展览会在深圳国际会展中心&#xff08;宝安新馆&#xff09;隆重举行。来自全球各地1000余家企业参与展出&#xff0c;展出面积达8万㎡&#xff0c;吸引了众多业内专家、企业家以及广大观众前来观看…

《攻防演练》在没有基础安全能力的情况下如何做好蓝队防守

目的&#xff1a; 1、净化企业或机构的网络环境、强化网络安全意识&#xff1b; 2、防攻击、防破坏、防泄密、防重大网络安全故障&#xff1b; 3、检验企业关键基础设施的安全防护能力&#xff1b; 4、提升关键基础设施的网络安全防范能力和水平。 现状&#xff1a; 那么问…

什么是 prompts, completions, and tokens

从字面上看&#xff0c;任何文本都可以用作提示(prompts)——输入一些文本然后得到一些文本。 我们虽然知道 GPT-3 对随机字符串的处理很有趣&#xff0c;但是编写一个有效的提示才能更好的真正的让GPT理解我们要它做什么。 提示&#xff08;prompts&#xff09; Prompt是怎么…

DHTMLX Gantt入门使用教程【引入】:如何开始使用 dhtmlxGantt

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求&#xff0c;具备完善的甘特图图表库&#xff0c;功能强大&#xff0c;价格便宜&#xff0c;提供丰富而灵活的JavaScript API接口&#xff0c;与各种服务器端技术&am…

vue3插槽的使用

插槽就是子组件中的提供给父组件使用的一个占位符&#xff0c;用 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&#xff0c;填充的内容会替换子组件的标签。 1.插槽基本使用 子组件SlotComponent.vue <template><div cla…

Salesforce Admin管理员中文学习教程_如何高效筛选出具有Admin权限的用户!

组织中最常见的错误之一就是拥有太多具有系统管理员简档的用户。不幸的是&#xff0c;这在某些行业中非常普遍。 实际上这存在着很大的潜在风险。拥有这些权限的用户可能会暴露、窃取或删除组织中的数据&#xff0c;甚至影响到其他用户。防止过多的管理员访问权限是保护Salesf…

CSDN博客写作编辑器如何使用?

文章目录0.引言1.快捷键2.文字3.链接和代码4.注脚和注释5.公式6.表7.图0.引言 笔者阅读CSDN博客已有五年&#xff0c;从最初的学习跟随者&#xff0c;到现在的CSDN博客创造者&#xff0c;这其中的转变来源于自身发展的思考&#xff0c;有学的输入&#xff0c;又有创作的输出&am…

GPT关键词挖掘,自动关键词文章生成

随着互联网的发展&#xff0c;内容营销已成为企业营销策略中不可或缺的一环。有效的关键词文章生成可以帮助企业吸引更多的潜在客户&#xff0c;提高品牌曝光度和转化率&#xff0c;从而实现营销目标。 关键词文章生成是指根据特定的关键词和主题&#xff0c;使用软件工具自动生…