zoukankan      html  css  js  c++  java
  • bytedance专题

    一 挑战字符串

    1 无重复字符的最长子串(见leetcode bug free)

    2 最长公共前缀(见leetcode bug free)

     3 字符串的排列

    给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

    示例1:
    输入: s1 = "ab" s2 = "eidbaooo"
    输出: True
    解释: s2 包含 s1 的排列之一 ("ba").
    
    示例2:
    输入: s1= "ab" s2 = "eidboaoo"
    输出: False
    View Code

    analyse:

    滑动窗口
    View Code

    code:

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1 == null || s2 == null || s1.length() > s2.length()) {
                return false;
            }   
            int[] map1 = new int[26];
            int[] map2 = new int[26];
            int i = 0;
            int j = 0;
            while (j < s1.length()) {
                char c1 = s1.charAt(j);
                char c2 = s2.charAt(j);
                map1[c1 - 'a'] += 1;
                map2[c2 - 'a'] += 1;
                j++;
            }   
            j = s1.length() - 1;
            while (j < s2.length()) {
                if (arrayEqual(map1, map2)) {
                    return true;
                }   
                j++;
                i++;
                if (j < s2.length()) {
                    char new_c = s2.charAt(j);
                    char old_c = s2.charAt(i - 1); 
                    map2[new_c - 'a'] += 1;
                    map2[old_c - 'a'] -= 1;
                }   
            }   
            return false;
        }   
        public boolean arrayEqual(int[] a, int[] b) {
            for (int i = 0; i < a.length; i++) {
                if (a[i] != b[i]) {
                    return false;
                }   
            }   
            return true;
        }
    }
    View Code

    4 字符串相乘

    两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。不能直接将字符串转化为大整数求乘积。

    示例 1:
    
    输入: num1 = "2", num2 = "3"
    输出: "6"
    示例 2:
    
    输入: num1 = "123", num2 = "456"
    输出: "56088"
    说明:
    
    num1 和 num2 的长度小于110。
    num1 和 num2 只包含数字 0-9。
    num1 和 num2 均不以零开头,除非是数字 0 本身。
    不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
    View Code

    analyse:

    要求结果里的第k个数字(k从0开始,k为0时表示个位,1表示十位),需要将满足i + j = k的所有数字乘积累加,再加上carry。(i和j分别为num1和num2的第i和第j个数字,定义同k)
    View Code

    code:

    class Solution {
        public String multiply(String num1, String num2) {
            if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) {
                return null;
            }   
            if (num1.equals("0") || num2.equals("0")) {
                return "0";
            }   
            int m = num1.length();
            int n = num2.length();
    
            StringBuilder sb = new StringBuilder();
            int k = 0;
            int carry = 0;
            while (k <= m + n - 2) {
                int sum = 0;
                for (int i = 0; i <= Math.min(k, m - 1); i++) {
                    int j = k - i;
                    if (j >= n) {
                        continue;
                    }   
                    int digit1 = num1.charAt(m - i - 1) - '0';
                    int digit2 = num2.charAt(n - j - 1) - '0';
                    sum += digit1 * digit2;
                }   
                sum += carry;
                sb.append(String.valueOf(sum % 10));
                carry = sum / 10; 
                k++;
            }   
            if (carry != 0) {
                String cs = String.valueOf(carry);
                String r_cs = (new StringBuilder(cs)).reverse().toString();
                sb.append(r_cs);
            }   
            return sb.reverse().toString();
        }   
    }
    View Code

    5 反转字符串

    给定一个字符串,逐个翻转字符串中的每个单词。

    示例 1:
    
    输入: "the sky is blue"
    输出: "blue is sky the"
    示例 2:
    
    输入: "  hello world!  "
    输出: "world! hello"
    解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
    示例 3:
    
    输入: "a good   example"
    输出: "example good a"
    解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
     
    
    说明:
    
    无空格字符构成一个单词。
    输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
    如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
    View Code

    analyse:

    几个要点:
    (1)定义两个指针p1,p2,p1指向待填充元素的位置,p2往后扫。
    (2)如何保证开头的空格被去掉:当p1为0时,p2扫到空格不加入。
    (3)如何保证单词间的空格只剩一个: 当p1 - 1为空格时,p2扫到空格不加入。
    (4)如何实现单词反转:实现一个字符串反转的方法。每次往前加入一个空格时,就反转一下上一个加入的单词。最后还要对整体反转一遍。
    (5)如何保证末尾的空格被去掉:扫完一遍后,检查p1-1是否为空格,是就p--。不是记得反转一下最后一个单词。
    View Code

    code:

    class Solution {
        public String reverseWords(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            char[] sa = s.toCharArray();
            int p = 0;
            int last_word_start = 0;
            for (int i = 0; i < sa.length; i++) {
                char c = sa[i];
                if (c == ' ') {
                    if (p == 0 || sa[p - 1] == ' ') {
                        continue;
                    }
                    reverse(sa, last_word_start, p - 1);
                    sa[p++] = c;
                    last_word_start = p;
                } else {
                    sa[p++] = c;
                }
            }
            if (p > 0 && sa[p - 1] == ' ') {
                p--;
            } else {
                reverse(sa, last_word_start, p - 1);
            }
            reverse(sa, 0, p - 1);
            return new String(sa, 0, p);
        }
        public void reverse(char[] sa, int start, int end) {
            while (start < end) {
                char tmp = sa[start];
                sa[start] = sa[end];
                sa[end] = tmp;
                start++;
                end--;
            }
        }
    }
    View Code

    6 简化路径

    题目太长

    以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
    
    在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
    
    请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
    
     
    
    示例 1:
    
    输入:"/home/"
    输出:"/home"
    解释:注意,最后一个目录名后面没有斜杠。
    示例 2:
    
    输入:"/../"
    输出:"/"
    解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
    示例 3:
    
    输入:"/home//foo/"
    输出:"/home/foo"
    解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
    示例 4:
    
    输入:"/a/./b/../../c/"
    输出:"/c"
    示例 5:
    
    输入:"/a/../../b/../c//.//"
    输出:"/c"
    示例 6:
    
    输入:"/a//b////c/d//././/.."
    输出:"/a/b/c"
    View Code

    analyse:

    先根据“/”split,遍历split后的每个元素,用一个栈来搞,
    View Code

    code:

    class Solution {
        public String simplifyPath(String path) {
            Stack<String> s = new Stack<String>();
            String[] dirs = path.split("/");
            for (String dir : dirs) {
                if (dir.equals("") || dir.equals(".")) {
                    continue;
                } else if (dir.equals("..")) {
                    if (!s.isEmpty()) {
                        s.pop();
                    }
                } else {
                    s.push(dir);
                }
            }
            if (s.isEmpty()) {
                return "/";
            }
            List<String> dir_list = new ArrayList<String>();
            while (!s.isEmpty()) {
                dir_list.add(s.pop());
            }
            StringBuilder sb = new StringBuilder();
            for (int i = dir_list.size() - 1; i >= 0; i--) {
                sb.append("/");
                sb.append(dir_list.get(i));
            }
            return sb.toString();
        }
    }
    View Code

    7  复原IP地址

    给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。(ip格式:只能是四段,每段值范围在0~255,除0外不能以0开头)。

    示例:
    
    输入: "25525511135"
    输出: ["255.255.11.135", "255.255.111.35"]
    View Code

    analyse:

    dfs
    View Code

    code:

    class Solution {
        public List<String> restoreIpAddresses(String s) {
            List<String> res = new ArrayList<String>();
            helper(res, s, 0, "", 0); 
            return res;
        }   
        public void helper(List<String> res, String s, int index, String cur, int count) {
            if (count == 4) {
                if (index >= s.length()) {
                    res.add(cur.substring(0, cur.length() - 1));
                } else {
                    return;
                }   
            }   
            for (int i = index; i < s.length(); i++) {
                if (i - index > 2) {
                    break;
                }   
                String p = s.substring(index, i + 1); 
                int pv = Integer.parseInt(p);
                if (pv > 255 || (p.charAt(0) == '0' && p.length() > 1)) {
                    continue;
                }   
                helper(res, s, i + 1, cur + p + ".", count + 1); 
            }   
        }   
    }
    View Code

    二 数组与排序

    1 岛屿的最大面积

    给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。

    找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)

    示例 1:
    
    [[0,0,1,0,0,0,0,1,0,0,0,0,0],
     [0,0,0,0,0,0,0,1,1,1,0,0,0],
     [0,1,1,0,1,0,0,0,0,0,0,0,0],
     [0,1,0,0,1,1,0,0,1,0,1,0,0],
     [0,1,0,0,1,1,0,0,1,1,1,0,0],
     [0,0,0,0,0,0,0,0,0,0,1,0,0],
     [0,0,0,0,0,0,0,1,1,1,0,0,0],
     [0,0,0,0,0,0,0,1,1,0,0,0,0]]
    对于上面这个给定矩阵应返回 6。注意答案不应该是11,因为岛屿只能包含水平或垂直的四个方向的‘1’。
    
    示例 2:
    
    [[0,0,0,0,0,0,0,0]]
    对于上面这个给定的矩阵, 返回 0。
    
    注意: 给定的矩阵grid 的长度和宽度都不超过 50。
    View Code

    analyse:

    并查集
    View Code

    code:

    class Solution {
        int[] father;
        int[] size;
        int max_size;
        public int maxAreaOfIsland(int[][] grid) {
            int m = grid.length;
            int n = grid[0].length;
            father = new int[m * n];
            size = new int[m * n];
            max_size = 0;
            for (int i = 0; i < m * n; i++) {
                father[i] = i;
                size[i] = 1;
            }   
            int[] dx = {0, 0, -1, -1};
            int[] dy = {1, -1, 0, 0};
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    int index = i * n + j;
                    if (grid[i][j] == 0) {
                        continue;
                    }
                    max_size = Math.max(1, max_size);
                    for (int k = 0; k < 4; k++) {
                        int nx = i + dx[k];
                        int ny = j + dy[k];
                        if (nx >= 0 && nx < m && ny >= 0
                          && ny < n && grid[nx][ny] == 1) {
                            union(index, nx * n + ny);
                        }
                    }
                }
            }
            return max_size;
        }
        public int find(int a) {
            if (father[a] == a) {
                return a;
            }
            return father[a] = find(father[a]);
        }
    
        public void union(int a, int b) {
            int root_a = find(a);
            int root_b = find(b);
            if (root_a != root_b) {
                father[root_a] = root_b;
                size[root_b] += size[root_a];
                max_size = Math.max(max_size, size[root_b]);
            }
        }
    }
    View Code

    2 最长连续递增序列

    给定一个未经排序的整数数组,找到最长且连续的的递增序列。

    示例 1:
    
    输入: [1,3,5,4,7]
    输出: 3
    解释: 最长连续递增序列是 [1,3,5], 长度为3。
    尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。 
    示例 2:
    
    输入: [2,2,2,2,2]
    输出: 1
    解释: 最长连续递增序列是 [2], 长度为1。
    注意:数组长度不会超过10000。
    View Code

    analyse:

    遍历即可
    View Code

    code:

    class Solution {
        public int findLengthOfLCIS(int[] nums) {
            if (nums == null || nums.length == 0) {
                return 0;
            }
            int start = 0;
            int res = 1;
            for (int i = 1; i < nums.length; i++) {
                if (nums[i - 1] >= nums[i]) {
                    start = i;
                }
                res = Math.max(res, i - start + 1);
            }
            return res;
        }
    }
    View Code

    3 最长连续序列

    给定一个未排序的整数数组,找出最长连续序列的长度。

    示例:
    
    输入: [100, 4, 200, 1, 3, 2]
    输出: 4
    解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
    View Code

    analyse:

    带size的并查集和hash表
    View Code

    code:

    class Solution {
        int[] father;
        int[] size;
        int max_size;
        public int longestConsecutive(int[] nums) {
            if (nums == null || nums.length == 0) {
                return 0;
            }
            Map<Integer, Integer> map = new HashMap<Integer, Integer>();
            father = new int[nums.length];
            size = new int[nums.length];
            max_size = 1;
            for (int i = 0; i < nums.length; i++) {
                father[i] = i;
                size[i] = 1;
            }
            for (int i = 0; i < nums.length; i++) {
                if (map.containsKey(nums[i])) {
                    continue;
                }
                if (map.containsKey(nums[i] - 1)) {
                    union(map.get(nums[i] - 1), i);
                }
                if (map.containsKey(nums[i] + 1)) {
                    union(map.get(nums[i] + 1), i);
                }
                map.put(nums[i], i);
            }
            return max_size;
        }
        
        public int find(int a) {
            if (father[a] == a) {
                return a;
            }
            return father[a] = find(father[a]);
        }
        
        public void union(int a, int b) {
            int root_a = find(a);
            int root_b = find(b);
            if (root_a != root_b) {
                father[root_a] = root_b;
                size[root_b] += size[root_a];
                max_size = Math.max(size[root_b], max_size);
            }
        }
    }
    View Code

    4 朋友圈

    班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
    
    给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
    
    示例 1:
    
    输入: 
    [[1,1,0],
     [1,1,0],
     [0,0,1]]
    输出: 2 
    说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
    第2个学生自己在一个朋友圈。所以返回2。
    示例 2:
    
    输入: 
    [[1,1,0],
     [1,1,1],
     [0,1,1]]
    输出: 1
    说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。
    注意:
    
    N 在[1,200]的范围内。
    对于所有学生,有M[i][i] = 1。
    如果有M[i][j] = 1,则有M[j][i] = 1。
    View Code

    analyse:

    即求无向图的连通块数量,bfs或并查集
    View Code

    code:

    class Solution {
    
        public int findCircleNum(int[][] M) {
            Set<Integer> set = new HashSet<Integer>();
            int count = 0;
            int n = M.length;
            for (int i = 0; i < n; i++) {
                if (set.contains(i)) {
                    continue;
                }
                count++;
                Queue<Integer> q = new LinkedList<Integer>();
                q.offer(i);
                set.add(i);
                while (!q.isEmpty()) {
                    int cur = q.poll();
                    for (int j = 0; j < n; j++) {
                        if (M[cur][j] == 1 && !set.contains(j)) {
                            q.offer(j);
                            set.add(j);
                        }
                    }
                }
            }
            return count;
        } 
    }
    View Code
    class Solution {
        int[] father;
        int count;
        public int findCircleNum(int[][] M) {
            int n = M.length;
            father = new int[n];
            count = n;
            for (int i = 0; i < n; i++) {
                father[i] = i;
            }
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (M[i][j] == 1) {
                        union(i, j);
                    }
                }
            }
            return count;
        }
        
        public int find(int a) {
            if (father[a] == a) {
                return a;
            }
            return father[a] = find(father[a]);
        }
        
        public void union(int a, int b) {
            int root_a = find(a);
            int root_b = find(b);
            if (root_a != root_b) {
                father[root_a] = root_b;
                count--;
            }
        }
    }
    View Code

    5 合并区间(见leetcode bug free)

    6 接雨水

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

    analyse:

    两个指针指向两边已经灌完水的柱子,灌水的时候从两边往中间灌,哪边低就先灌哪边。
    View Code

    code:

    class Solution {
        public int trap(int[] height) {
            if (height == null || height.length <= 2) {
                return 0;
            }   
            int i = 0;
            int j = height.length - 1;
            int res = 0;
            int left = 0;
            int right = 0;
            while (i + 1 < j) {
                 if (height[i] + left < height[j] + right) {
                     left = Math.max(height[i] + left - height[i + 1], 0); 
                     res += left;
                     i++;
                 } else {
                     right = Math.max(height[j] + right - height[j - 1], 0); 
                     res += right;
                     j--;
                 }   
            }   
            return res;
        }   
    }
    View Code

    7 第k个排列

    给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
    
    按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
    
    "123"
    "132"
    "213"
    "231"
    "312"
    "321"
    给定 n 和 k,返回第 k 个排列。
    
    说明:
    
    给定 n 的范围是 [1, 9]。
    给定 k 的范围是[1,  n!]。
    示例 1:
    
    输入: n = 3, k = 3
    输出: "213"
    示例 2:
    
    输入: n = 4, k = 9
    输出: "2314"
    View Code

    analyse:

    递归。首先把1~n加入到list中,求第一个数时,设i = k - 1, 应该找list.get(i / (n - 1)!),然后list删除这个数,i设为i % (n - 1)!。类似的接下来去找第2~n个数。
    View Code

    code:

    class Solution {
        public String getPermutation(int n, int k) {
            int factorial = 1;
            List<Integer> numbers = new ArrayList<Integer>();
            for (int i = 1; i <= n; i++) {
                factorial *= i;
                numbers.add(i);
            }   
            StringBuilder sb = new StringBuilder();
            helper(sb, k - 1, numbers, factorial / n);
            return sb.toString();
        }   
        public void helper(StringBuilder sb, int i, List<Integer> numbers, int factorial) {
            int num_index = i / factorial;
            sb.append(numbers.get(num_index));
            numbers.remove(num_index);
            if (numbers.size() == 0) {
                return;
            }   
            helper(sb, i % factorial, numbers, factorial / numbers.size());
        }   
    }   
    View Code

    四 动态和贪心

    1 最大正方形(见leetcode bug free)

    2 俄罗斯套娃信封问题

    给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
    
    请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
    
    说明:
    不允许旋转信封。
    
    示例:
    
    输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
    输出: 3 
    解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
    View Code

    analyse:

    先把信封按宽度从小到大排序,dp状态dp[i]表示为第i个信封为最外层信封时的最大信封数。
    View Code

    code:

    class Solution {
        public int maxEnvelopes(int[][] envelopes) {
            if (envelopes == null || envelopes.length == 0) {
                return 0;
            }
            List<Pair> list = new ArrayList<Pair>();
    
            for (int i = 0; i < envelopes.length; i++) {
                list.add(new Pair(envelopes[i][0], envelopes[i][1]));
            }
            Comparator<Pair> c = new Comparator<Pair>() {
                public int compare(Pair e1, Pair e2) {
                    return e1.w - e2.w;
                }
            };
            Collections.sort(list, c);
            int[] dp = new int[envelopes.length];
    
            int res = 1;
            for (int i = 0; i < dp.length; i++) {
                Pair cur = list.get(i);
                dp[i] = 1;
                for (int j = 0; j < i; j++) {
                    Pair last = list.get(j);
                    if (cur.w > last.w && cur.h > last.h) {
                        dp[i] = Math.max(dp[i], 1 + dp[j]);
                    }
                }
                res = Math.max(res, dp[i]);
            }
            return res;
        }
    }
    class Pair {
        int w;
        int h;
        Pair(int w, int h) {
            this.w = w;
            this.h = h;
        }
    }
    View Code

    五 数据结构

    1 全O(1)的数据结构

    实现一个数据结构支持以下操作:
    
    Inc(key) - 插入一个新的值为 1 的 key。或者使一个存在的 key 增加一,保证 key 不为空字符串。
    Dec(key) - 如果这个 key 的值是 1,那么把他从数据结构中移除掉。否者使一个存在的 key 值减一。如果这个 key 不存在,这个函数不做任何事情。key 保证不为空字符串。
    GetMaxKey() - 返回 key 中值最大的任意一个。如果没有元素存在,返回一个空字符串""。
    GetMinKey() - 返回 key 中值最小的任意一个。如果没有元素存在,返回一个空字符串""。
    挑战:以 O(1) 的时间复杂度实现所有操作。
    View Code

    analyse:

    (1)两个map
    map1存key到count的映射关系
    map2存count到DoubleListNode的映射关系
    
    (2)DoubleListNode
    存对应的count,以及该count对应哪些key,以及prev和next
    
    (3)插入key时,做以下几件事:
    a 更新map1,更新后假设该key的频次为count
    b 找到count - 1对应的节点,记该节点为prev
    c 删除prev中该key
    d 假设prev的next节点的val不是count,需要新建一个节点,插入到prev后面
    f prev.next加入key
    g 假设prev中key数量已经被删除到0了,则删除prev这个节点(如果当前count为1则不删除)
    
    (4)删除key:类似于(3)
    (5)getMaxKey
    获取tail.prev.keys中的任意一个元素
    (6)getMinKey
    获取head.next.keys中的任意一个元素
    View Code

    code:

    class AllOne {
        Map<String, Integer> map1;
        Map<Integer, DoubleListNode> map2;
        DoubleListNode head;
        DoubleListNode tail;
    
        public AllOne() {
            map1 = new HashMap<String, Integer>();
            map2 = new HashMap<Integer, DoubleListNode>();
            head = new DoubleListNode(0, new HashSet<String>());
            tail = new DoubleListNode(0, new HashSet<String>());
            head.next = tail;
            tail.prev = head;
            map2.put(0, head);
        }
    
        public void inc(String key) {
            if (!map1.containsKey(key)) {
                map1.put(key, 0);
            }
            map1.put(key, map1.get(key) + 1);
    
            int count = map1.get(key);
            DoubleListNode prev = map2.get(count - 1);
            prev.keys.remove(key);
    
            if (prev.next.val != count) {
                DoubleListNode new_n = new DoubleListNode(count, new HashSet<String>());
                map2.put(count, new_n);
                insertAfterPos(prev, new_n);
            }
            prev.next.keys.add(key);
    
            if (prev.keys.size() == 0 && count != 1) {
                deleteNode(prev);
                map2.remove(count - 1);
            }
        }
    
        public void dec(String key) {
            if (!map1.containsKey(key)) {
                return;
            }
            int count = map1.get(key) - 1;
    
            map1.remove(key);
            DoubleListNode next = map2.get(count + 1);
            next.keys.remove(key);
            for (String s : map1.keySet()) {
                System.out.println(s);
            }
            if(count != 0) {
                map1.put(key, count);
                if (next.prev.val != count) {
                    DoubleListNode new_n = new DoubleListNode(count, new HashSet<String>());
                    map2.put(count, new_n);
                    insertBeforePos(next, new_n);
                }
                next.prev.keys.add(key);
            }
            if (next.keys.size() == 0) {
                deleteNode(next);
                map2.remove(count + 1);
            }
        }
    
        public String getMaxKey() {
            if (map1.size() == 0) {
                return "";
            }
            return tail.prev.keys.iterator().next();
        }
    
        public String getMinKey() {
            if (map1.size() == 0) {
                return "";
            }
            return head.next.keys.iterator().next();
        }
    
        private void deleteNode(DoubleListNode node) {
            DoubleListNode prev = node.prev;
            DoubleListNode next = node.next;
            prev.next = next;
            next.prev = prev;
        }
    
        private void insertAfterPos(DoubleListNode pos, DoubleListNode node) {
            DoubleListNode pos_next = pos.next;
            pos.next = node;
            pos_next.prev = node;
            node.prev = pos;
            node.next = pos_next;
        }
    
        private void insertBeforePos(DoubleListNode pos, DoubleListNode node) {
            DoubleListNode pos_prev = pos.prev;
            pos.prev = node;
            pos_prev.next = node;
            node.prev = pos_prev;
            node.next = pos;
        }
    }
    
    class DoubleListNode {
        int val;
        Set<String> keys;
        DoubleListNode next;
        DoubleListNode prev;
        DoubleListNode(int val, Set<String> keys) {
            this.val = val;
            this.keys = keys;
        }
    }
    View Code

    六 扩展练习

    1 平方根

    实现 int sqrt(int x) 函数
    View Code

    analyse:

    二分,注意用long防止溢出
    View Code

    code:

    class Solution {
        public int mySqrt(int x) {
            long start = 0;
            long end = x;
            while (start + 1 < end) {
                long mid = (start + end) / 2;
                if (mid * mid <= x) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (end * end <= x) {
                return (int)end;
            }
            return (int)start;
        }
    }
    View Code
  • 相关阅读:
    项目01-nginx模块
    Spark机器学习
    项目01-手机端模块
    Spark内存管理
    Spark Streaming
    Spark SQL
    Spark Job调度
    Spark master节点HA配置
    机器学习
    07、Spark集群的进程管理
  • 原文地址:https://www.cnblogs.com/coldyan/p/11343756.html
Copyright © 2011-2022 走看看