leetcode刷题 538~

题目538题

把二叉搜素树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。

思路

深度优先遍历

实现

class Solution {
    public TreeNode convertBST(TreeNode root) {
        int a = dfs(root,0);
        return root;
    }

    private int dfs(TreeNode node, int bigger){
        int right = 0;
        if(node == null){
            return 0;
        }
        
        right = dfs(node.right, bigger);
        if(node.right == null)
            node.val += bigger;
        node.val += right;
        int left = dfs(node.left, node.val);
        if(left != 0){
            return left;
        }
        return node.val;
    }
}

题目539题

最小时间差

给定一个 24 小时制(小时:分钟 "HH:MM")的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。

思路实现

class Solution {
    public int findMinDifference(List<String> timePoints) {
        if (timePoints.size()>=1440){
            return 0;
        }
        int[] timeList = new int[timePoints.size()];
        for(int index=0; index < timePoints.size(); index++){
            String[] time = timePoints.get(index).split(":");
            int hour = Integer.parseInt(time[0]);
            int minute = Integer.parseInt(time[1]);
            timeList[index] = hour*60 + minute;
        }
        Arrays.sort(timeList);
        int res = 1440;
        for(int index=1; index < timePoints.size(); index++){
            res = Math.min(res, timeList[index]- timeList[index-1]);
            if(res == 0){
                return 0;
            }
        }
        res = Math.min(res, 1440 - timeList[timeList.length - 1] + timeList[0]);
        return res;
    }
}

题目540题

有序数组中的单一元素

给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。

示例 1:

输入: [1,1,2,3,3,4,4,8,8]
输出: 2

思路

二分法

实现

class Solution {
    public int singleNonDuplicate(int[] nums) {
        int left =0, right = nums.length -1;
        int mid=0;
        while(left < right){
            if(nums[left] != nums[left+1]){
                mid = left;
                break;
            }else if(nums[right] != nums[right-1]){
                mid = right;
                break;
            }else{
                mid = left + (right-left)/2;
            }
            int halflen = (right - left)/2;
            if(halflen %2==0 && nums[mid]==nums[mid-1]){
                right = mid - 2;
            }else if(halflen %2==0 && nums[mid]==nums[mid+1]){
                left = mid + 2;
            }else if(halflen %2==1 && nums[mid]==nums[mid-1]){
                left = mid + 1;
            }else if(halflen %2==1 && nums[mid]==nums[mid+1]){
                right = mid - 1;
            }else{
                break;
            }
        }
        return nums[mid];
    }
}

题目541题

反转字符串II

给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例:

输入: s = "abcdefg", k = 2
输出: "bacdfeg"

思路实现

class Solution {
    public String reverseStr(String s, int k) {
        char[] c = s.toCharArray();
        for(int index = 0; index < c.length; index += 2*k){
            int i = index, j = Math.min(index + k - 1, c.length - 1);
            while (i < j) {
                char tmp = c[i];
                c[i++] = c[j];
                c[j--] = tmp;
            }
        }
        return String.valueOf(c);
    }
}

题目542题

01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

示例 1:

输入:
[[0,0,0],
[0,1,0],
[0,0,0]]

输出:
[[0,0,0],
 [0,1,0],
 [0,0,0]]

思路

1. 深度优先遍历

实现

class Solution {
    private int[][] matrix;
    private int row, col;
    int [][]dirs={{-1,0},{1,0},{0,-1},{0,1}};
    public int[][] updateMatrix(int[][] matrix) {
        this.matrix = matrix;
        row = matrix.length;
        col = matrix[0].length;
        for(int i=0; i < row; i++){
            for(int j=0; j < col; j++ ){
                if(this.matrix[i][j] ==1 && !hasNeighbors0(i,j)){
                    this.matrix[i][j] = Integer.MAX_VALUE;
                }
            }
        }
        for(int i=0; i < row; i++){
            for(int j=0; j < col; j++ ){
                if(this.matrix[i][j] == 1){
                    dfs(i, j);
                }
            }
        }

        return this.matrix;
    }

    boolean hasNeighbors0(int x,int y){ 
        for(int[] dir:dirs){
            int new_x=x+dir[0];
            int new_y=y+dir[1];
            if(new_x>=0 && new_x<row && new_y>=0 && new_y<col && matrix[new_x][new_y]==0)
                return true;
        }
         return false;
    }

    private void dfs(int x ,int y){
        for(int[] dir:dirs){
            int new_x=x+dir[0];
            int new_y=y+dir[1];
            if(new_x>=0 && new_x<row && new_y>=0 && new_y<col && matrix[new_x][new_y]>matrix[x][y]+1 ){
            matrix[new_x][new_y] = matrix[x][y]+1;
            dfs(new_x, new_y);
            }
        }
    }

}

题目543题

二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 :
给定二叉树

1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

思路实现

class Solution {
    int res = 1;
    public int diameterOfBinaryTree(TreeNode root) {
        calcLen(root);
        return res-1;
    }

    private int calcLen(TreeNode node){
        if (node == null){
            return 0;
        }
        int resleft = calcLen(node.left);
        int resright = calcLen(node.right);
        res = Math.max(resleft + resright+ 1, res);
        return Math.max(resleft, resright)+1;
    }
}

题目547题

朋友圈

班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

思路

1.广度优先遍历

2.Union-Find算法

实现

1.
class Solution {
    public int findCircleNum(int[][] M) {
        int N = M.length;
        int res = 0;
        boolean[] visited = new boolean[N];
        Queue<Integer> queue = new LinkedList<Integer>();
        for(int i=0; i < N; i++){
            if(visited[i] == false){
                res +=1;
                queue.offer(i);
                while(queue.size()!= 0){
                    int j = queue.poll();
                    visited[j] = true;
                    for(int k=0; k <N; k++){
                        if(M[j][k] == 1 && visited[k] == false){
                            queue.offer(k);
                        }
                    }
                }
            }
        }
        return res;
    }
}
2.
class Solution {
    class UF {
    // 记录连通分量个数
    private int count;
    // 存储若干棵树
    private int[] parent;
    // 记录树的“重量”
    private int[] size;

    public UF(int n) {
        this.count = n;
        parent = new int[n];
        size = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
            size[i] = 1;
        }
    }
    
    /* 将 p 和 q 连通 */
    public void union(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);
        if (rootP == rootQ)
            return;
        
        // 小树接到大树下面,较平衡
        if (size[rootP] > size[rootQ]) {
            parent[rootQ] = rootP;
            size[rootP] += size[rootQ];
        } else {
            parent[rootP] = rootQ;
            size[rootQ] += size[rootP];
        }
        count--;
    }

    /* 判断 p 和 q 是否互相连通 */
    public boolean connected(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);
        // 处于同一棵树上的节点,相互连通
        return rootP == rootQ;
    }

    /* 返回节点 x 的根节点 */
    private int find(int x) {
        while (parent[x] != x) {
            // 进行路径压缩
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }
    
    public int count() {
        return count;
    }
}

        public int findCircleNum(int[][] M) {
        int n = M.length;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (M[i][j] == 1)
                    uf.union(i, j);
            }
        }
        return uf.count();
    }

}
 

题目551题

学生出勤记录I

给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符:

'A' : Absent,缺勤
'L' : Late,迟到
'P' : Present,到场
如果一个学生的出勤记录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。

你需要根据这个学生的出勤记录判断他是否会被奖赏。

思路实现

class Solution {
    public boolean checkRecord(String s) {
        char[] c = s.toCharArray();
        int a = 0;
        int l = 0;
        for(char i: c){
            if(i == 'A'){
                a += 1;
                l = 0;
            }else if(i == 'L'){
                l += 1;
            }else{
                l = 0;
            }
            if(a > 1 || l >2){
                return false;
            }
        }
        return true;
    }
}

题目553题

最优除法

给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [2,3,4] -> 2 / 3 / 4 。

但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级。你需要找出怎么添加括号,才能得到最大的结果,并且返回相应的字符串格式的表达式。你的表达式不应该含有冗余的括号。

示例:

输入: [1000,100,10,2]
输出: "1000/(100/10/2)"
解释:
1000/(100/10/2) = 1000/((100/10)/2) = 200
但是,以下加粗的括号 "1000/((100/10)/2)" 是冗余的,
因为他们并不影响操作的优先级,所以你需要返回 "1000/(100/10/2)"。

思路

数学降维打击:为了最大化 a/b/c/da/b/c/d 我们首先需要最小化 b/c/d,现在我们的目标变成了最小化表达式 b/c/d。而b/c/d就是最小值。因此对于形如 a/b/c/d/e/f... 的表达式,答案将是 a/(b/c/d/e/f...)

实现

class Solution {
    public String optimalDivision(int[] nums) {
        if (nums.length == 1)
            return nums[0] + "";
        if (nums.length == 2)
            return nums[0] + "/" + nums[1];
        StringBuilder res = new StringBuilder(nums[0] + "/(" + nums[1]);
        for (int i = 2; i < nums.length; i++) {
            res.append("/" + nums[i]);
        }
        res.append(")");
        return res.toString();
    }
}

题目554题

砖墙

你的面前有一堵矩形的、由多行砖块组成的砖墙。 这些砖块高度相同但是宽度不同。你现在要画一条自顶向下的、穿过最少砖块的垂线。

砖墙由行的列表表示。 每一行都是一个代表从左至右每块砖的宽度的整数列表。

如果你画的线只是从砖块的边缘经过,就不算穿过这块砖。你需要找出怎样画才能使这条线穿过的砖块数量最少,并且返回穿过的砖块数量。

你不能沿着墙的两个垂直边缘之一画线,这样显然是没有穿过一块砖的。

示例:

输入: [[1,2,2,1],
[3,1,2],
[1,3,2],
[2,4],
[3,1,2],
[1,3,1,1]]

输出: 2

思路

哈希表

实现

class Solution {
    public int leastBricks(List<List<Integer>> wall) {
        HashMap<Integer, Integer> map = new  HashMap<Integer, Integer>();
        int sum = 0;
        List<Integer> first = wall.get(0);
        for(int num: first){
            sum += num;
        }
        for(List<Integer> level: wall){
            int cur = 0;
            for(int num: level){
                cur += num;
                if(cur < sum)
                    map.put(cur,1 + map.getOrDefault(cur,0));
            }
        }
        int max = 0;
        for(int num: map.values()){
            max = Math.max(max, num);
        }
        return wall.size() - max;
    }
}

题目556题

下一个更大元素III

给定一个32位正整数 n,你需要找到最小的32位整数,其与 n 中存在的位数完全相同,并且其值大于n。如果不存在这样的32位整数,则返回-1。

示例 1:

输入: 12
输出: 21

思路实现

class Solution {
    public int nextGreaterElement(int n) {
        int[] t = new int[10];
        int l = t.length;
        int temp = n;
        while (l > 0 && temp > 0) {
            l--;
            t[l] = temp % 10;
            temp /= 10;
        }
        for(int i = t.length-1; i >l; i--){
            if(t[i-1] < t[i]){
                temp = i-1;
                int w = i-1;
                int[] min = new int[t.length-i];
                int k = 0;
                for(int j = t.length-1; j>w; j--){
                    if(t[j] <= t[temp] || temp != i-1){
                        min[k] = t[j];
                        k += 1;
                    }else{
                        min[k] = t[temp];
                        k += 1; 
                        temp = j;
                    }
                }
                t[w] = t[temp];
                for(int q = i, s=0; q<t.length; q++,s++){
                    t[q] = min[s];
                }
                break;
            }
        }
        int res = 0;
        for(int i: t){
            res = res*10+i;
        }
        return res <= n ? -1 : res;
    }


}

 

题目539题

思路实现

题目539题

思路实现

题目539题

思路实现

题目539题

思路实现

题目539题

思路实现

 

题目539题

思路实现

题目539题

思路实现

题目539题

思路实现

题目539题

思路实现

 

posted @ 2020-12-23 12:52  maoguai  阅读(78)  评论(0编辑  收藏  举报