【JAVA】力扣第197场周赛代码+解题思路

落花浮王杯 提交于 2020-07-28 19:54:49

如果你从本文中学习到丝毫知识,那么请您点点关注、点赞、评论和收藏
大家好,我是爱做梦的鱼,我是东北大学大数据实验班大三的小菜鸡,非常渴望优秀,羡慕优秀的人,个人博客为:爱做梦的鱼https://zihao.blog.csdn.net/

欢迎大家关注微信公众号【程序猿干货铺
一群热爱技术并且向往优秀的程序猿同学,不喜欢水文,不喜欢贩卖焦虑,只喜欢谈技术,分享的都是技术干货。Talk is cheap. Show me the code
在这里插入图片描述

5460. 好数对的数目

给你一个整数数组 nums 。
如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。
返回好数对的数目。

示例 1:
输入:nums = [1,2,3,1,1,3]
输出:4
解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始


示例 2:
输入:nums = [1,1,1,1]
输出:6
解释:数组中的每组数字都是好数对


示例 3:
输入:nums = [1,2,3]
输出:0

提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100

解题锦囊

Count how many times each number appears. If a number appears n times, then n * (n – 1) // 2 good pairs can be made with this number.

思路一:常规(未用解题锦囊)

代码

public class GoodNumber {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 1, 1, 3};
        System.out.print(new GoodNumber().numIdenticalPairs(a));
    }

    public int numIdenticalPairs(int[] nums) {
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] == nums[j]) {
                    count++;
                }
            }
        }
        return count;
    }
}

思路二:使用解题锦囊

5461. 仅含 1 的子串数

给你一个二进制字符串 s(仅由 ‘0’ 和 ‘1’ 组成的字符串)。

返回所有字符都为 1 的子字符串的数目。

由于答案可能很大,请你将它对 10^9 + 7 取模后返回。

示例 1:
输入:s = “0110111”
输出:9
解释:共有 9 个子字符串仅由 ‘1’ 组成
“1” -> 5 次
“11” -> 3 次
“111” -> 1 次





示例 2:
输入:s = “101”
输出:2
解释:子字符串 “1” 在 s 中共出现 2 次


示例 3:
输入:s = “111111”
输出:21
解释:每个子字符串都仅由 ‘1’ 组成


示例 4:
输入:s = “000”
输出:0

提示:

s[i] == ‘0’ 或 s[i] == ‘1’
1 <= s.length <= 10^5

解题锦囊

Count number of 1s in each consecutive-1 group. For a group with n consecutive 1s, the total contribution of it to the final answer is (n + 1) * n // 2.

代码

public class Only1s_2 {
    public static void main(String[] args) {
        System.out.println(new Only1s_2().numSub("0110111"));
        System.out.println(new Only1s_2().numSub("101"));
        System.out.println(new Only1s_2().numSub("111111"));
        System.out.println(new Only1s_2().numSub("000"));
        System.out.println(new Only1s_2().numSub("1111111111011010011"));
    }

    public int numSub(String s) {
        long count = 0;
        long sum = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '1') {
                count++;
            } else {
                sum = (sum + count * (count + 1) / 2) % 1000000007;
                count = 0;
            }
        }
        sum = (sum + count * (count + 1) / 2) % 1000000007;
        return (int) sum;
    }
}

错误点

在这里插入图片描述
在这里插入图片描述

public int numSub(String s) {
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '1') {
                count++;
                for (int j = i + 1; j < s.length(); j++) {
                    if (s.charAt(j) != '1') {
                        break;
                    } else {
                        count++;
                    }
                }
            }
        }
        return (int) (count % (1e9+ 7));
    }

5211. 概率最大的路径

给你一个由 n 个节点(下标从 0 开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b] 表示连接节点 a 和 b 的一条无向边,且该边遍历成功的概率为 succProb[i] 。

指定两个节点分别作为起点 start 和终点 end ,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。

如果不存在从 start 到 end 的路径,请 返回 0 。只要答案与标准答案的误差不超过 1e-5 ,就会被视作正确答案。

示例 1:
在这里插入图片描述
输入:n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2
输出:0.25000
解释:从起点到终点有两条路径,其中一条的成功概率为 0.2 ,而另一条为 0.5 * 0.5 = 0.25



示例 2:
在这里插入图片描述
输入:n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2
输出:0.30000


示例 3:
在这里插入图片描述
输入:n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2
输出:0.00000
解释:节点 0 和 节点 2 之间不存在路径



提示:
2 <= n <= 10^4
0 <= start, end < n
start != end
0 <= a, b < n
a != b
0 <= succProb.length == edges.length <= 2*10^4
0 <= succProb[i] <= 1
每两个节点之间最多有一条边







解题锦囊

  1. Multiplying probabilities will result in precision errors.
  2. Take log probabilities to sum up numbers instead of multiplying them.
  3. Use Dijkstra’s algorithm to find the minimum path between the two nodes after negating all costs.

代码

public class Path {
    public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
        ArrayList<double[]>[] graph = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<>();
        }
        for (int i = 0; i < edges.length; i++) {
            graph[edges[i][0]].add(new double[] { edges[i][1], succProb[i] });
            graph[edges[i][1]].add(new double[] { edges[i][0], succProb[i] });
        }
        PriorityQueue<double[]> queue = new PriorityQueue<>((a, b) -> Double.compare(b[1], a[1]));
        boolean[] visited = new boolean[n];
        queue.add(new double[] { start, 1 });
        while (!queue.isEmpty()) {
            double[] head = queue.remove();
            if (head[0] == end) {
                return head[1];
            } else if (!visited[(int) head[0]]) {
                visited[(int) head[0]] = true;
                for (double[] next : graph[(int) head[0]]) {
                    queue.add(new double[] { next[0], head[1] * next[1] });
                }
            }
        }
        return 0;
    }
}

5463. 服务中心的最佳位置

一家快递公司希望在新城市建立新的服务中心。公司统计了该城市所有客户在二维地图上的坐标,并希望能够以此为依据为新的服务中心选址:使服务中心 到所有客户的欧几里得距离的总和最小 。

给你一个数组 positions ,其中 positions[i] = [xi, yi] 表示第 i 个客户在二维地图上的位置,返回到所有客户的 欧几里得距离的最小总和 。

换句话说,请你为服务中心选址,该位置的坐标 [xcentre, ycentre] 需要使下面的公式取到最小值:

在这里插入图片描述

与真实值误差在 10^-5 之内的答案将被视作正确答案。

示例 1:
在这里插入图片描述
输入:positions = [[0,1],[1,0],[1,2],[2,1]]
输出:4.00000
解释:如图所示,你可以选 [xcentre, ycentre] = [1, 1] 作为新中心的位置,这样一来到每个客户的距离就都是 1,所有距离之和为 4 ,这也是可以找到的最小值。



示例 2:
在这里插入图片描述
输入:positions = [[1,1],[3,3]]
输出:2.82843
解释:欧几里得距离可能的最小总和为 sqrt(2) + sqrt(2) = 2.82843



示例 3:
输入:positions = [[1,1]]
输出:0.00000

示例 4:
输入:positions = [[1,1],[0,0],[2,0]]
输出:2.73205
解释:乍一看,你可能会将中心定在 [1, 0] 并期待能够得到最小总和,但是如果选址在 [1, 0] 距离总和为 3
如果将位置选在 [1.0, 0.5773502711] ,距离总和将会变为 2.73205
当心精度问题!




示例 5:
输入:positions = [[0,1],[3,2],[4,5],[7,6],[8,9],[11,1],[2,12]]
输出:32.94036
解释:你可以用 [4.3460852395, 4.9813795505] 作为新中心的位置


提示:
1 <= positions.length <= 50
positions[i].length == 2
0 <= positions[i][0], positions[i][1] <= 100


解题锦囊

  1. The problem can be reworded as, giving a set of points on a 2d-plane, return the geometric median.
  2. Loop over each triplet of points (positions[i], positions[j], positions[k]) where i < j < k, get the centre of the circle which goes throw the 3 points, check if all other points lie in this circle.

代码:

public class BestPosition {
    public double getMinDistSum(int[][] positions) {
        double[] current_point = new double[2];
        for (int[] position : positions) {
            current_point[0] += position[0];
            current_point[1] += position[1];
        }
        current_point[0] /= positions.length;
        current_point[1] /= positions.length;
        double minimum_distance = distSum(current_point, positions, positions.length);
        int k = 0;
        while (k < positions.length) {
            for (int i = 0; i < positions.length && i != k; i++) {
                double[] newpoint = new double[2];
                newpoint[0] = positions[i][0];
                newpoint[1] = positions[i][1];
                double newd = distSum(newpoint, positions, positions.length);
                if (newd < minimum_distance) {
                    minimum_distance = newd;
                    current_point[0] = newpoint[0];
                    current_point[1] = newpoint[1];
                }
            }
            k++;
        }
        double test_distance = 1000;
        int flag = 0;
        double[][] test_point = {{-1.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {0.0, -1.0}};
        while (test_distance > 0.0001) {
            flag = 0;
            for (int i = 0; i < 4; i++) {
                double[] newpoint = new double[2];
                newpoint[0] = current_point[0] + test_distance * test_point[i][0];
                newpoint[1] = current_point[1] + test_distance * test_point[i][1];
                double newd = distSum(newpoint, positions, positions.length);
                if (newd < minimum_distance) {
                    minimum_distance = newd;
                    current_point[0] = newpoint[0];
                    current_point[1] = newpoint[1];
                    flag = 1;
                    break;
                }
            }
            if (flag == 0)
                test_distance /= 2;
        }
        return minimum_distance;
    }

    private double distSum(double[] p, int[][] arr, int n) {
        double sum = 0;
        for (int i = 0; i < n; i++) {
            double distx = Math.abs(arr[i][0] - p[0]);
            double disty = Math.abs(arr[i][1] - p[1]);
            sum += Math.sqrt((distx * distx) + (disty * disty));
        }

        return sum;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!