LeetCode – 23 – 分数到小数 – 24~29 – 三角周,启动!

25 – 09 – 23 (补于 25 – 09 – 29)

今日份题面

给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数 。

如果小数部分为循环小数,则将循环的部分括在括号内。

如果存在多个答案,只需返回 任意一个 。

对于所有给定的输入,保证 答案字符串的长度小于 104 。

思路上其实只有一个难点:我们如何知道当前的结果是否是循环小数?

但其实也很容易想出来,因为除数始终是固定的,那么出现循环时所得的结果必定会在前面出现过。

那么很容易就想到了我们可以开一个 HashSet 维护出现过的当前位结果(注意不含补充 0 ),只要出现过就遍历当前拼接串,将第一次出现该结果的左边插入 ‘(‘, 末尾不插入当前结果(因为重复)而是插入 ‘)’

pass 实现:

class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if (numerator == 0) return "0";
        StringBuilder res = new StringBuilder();
        // 处理符号
        if ((numerator < 0) ^ (denominator < 0)) res.append('-');
        long num = Math.abs((long) numerator);
        long den = Math.abs((long) denominator);
        // 整数部分
        res.append(num / den);
        long remainder = num % den;
        if (remainder == 0) return res.toString();
        // 小数部分
        res.append('.');
        Map<Long, Integer> map = new HashMap<>();
        while (remainder != 0) {
            if (map.containsKey(remainder)) {
                res.insert(map.get(remainder), "(");
                res.append(')');
                break;
            }
            map.put(remainder, res.length());
            remainder *= 10;
            res.append(remainder / den);
            remainder %= den;
        }
        return res.toString();
    }
}

三角周,启动!

25 – 09 – 24 (补于 25 – 09 – 30)

今日份题面

三角形最小路径和

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

一道很经典的 DP 入门题,实际上是 IOI 的94年赛题变种,我们可以自顶向下 dp 也可以自底向上 dp,核心的状态方程可表示为:

dp[i][j] = Math.min(dp[i - 1][j - 1] + triangle.get(i - 1).get(j - 1), dp[i - 1][j] + triangle.get(i - 1).get(j));

秒了

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int res = Integer.MAX_VALUE, l = triangle.size();
        int [][] dp = new int [l][l];
        for(int [] i : dp){
            Arrays.fill(i, Integer.MAX_VALUE);
        }
        if(l <= 1) return triangle.get(0).get(0);
        dp[0][0] = 0; dp[1][0] = triangle.get(0).get(0); dp[1][1] = triangle.get(0).get(0);
        for(int i = 1; i < l; ++i){
            for(int j = 0; j <= i; ++j){
                if(j == i){
                    dp[i][j] = dp[i - 1][j - 1] + triangle.get(i - 1).get(j - 1);
                    continue;
                }else if (j == 0){
                    dp[i][j] = dp[i - 1][j] + triangle.get(i - 1).get(j);
                    continue;
                }
                dp[i][j] = Math.min(dp[i - 1][j - 1] + triangle.get(i - 1).get(j - 1), dp[i - 1][j] + triangle.get(i - 1).get(j));
            }
        }
        for(int i = 0; i < l; ++i){
            res = Math.min(res, dp[l - 1][i] + triangle.get(l - 1).get(i));
        }
        return res;
    }
}

25 – 09 – 25 (补于 25 – 10 – 01)

国庆快乐!

今日份题面

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

简明,扼要,但是不好搞。

当然我们可以暴力 $O(n^3)$ 一组一组进行比对,但只要数据量稍微大那么一丢丢就炸了。

所有另选思路。

构成三角形的必要条件是两边之和大于第三边,那么在边数有序的情况下,我们只需要考虑最大边是否小于其余两边之和就行了

所有考虑一个双指针,快指针维护当前最大边,慢指针维护最短边,两指针之间是中间边,当最短边和中间边之和小于最大边时最大边移动,大于最大边时记录当前组数

class Solution {
    public int triangleNumber(int[] nums) {
        int res = 0;
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; ++i){
            if(nums[i] == 0) continue;
            int k = i;
            for(int j = i + 1; j < nums.length; ++j){
                while(k + 1 < nums.length && nums[k + 1] - nums[j] < nums[i]){
                    ++k;
                } 
                res += Math.max(k - j, 0);
            }
        }
        return res;
    }
}

这样我们就相当于用一个不回头的隐形指针省去了一组遍历,实现了 $O(n^2)$ 的复杂度

以上


25 – 09 – 26 (补于 25 – 10 – 02)

今日份题面

给你一个由 X-Y 平面上的点组成的数组 points ,其中 points[i] = [xi, yi] 。从其中取任意三个不同的点组成三角形,返回能组成的最大三角形的面积。与真实值误差在 10-5 内的答案将会视为正确答案

我很难觉得这他妈是八(简)岁(单)?

后来一看数据范围,哦暴力吧

class Solution {
    public double largestTriangleArea(int[][] points) {
        int n = points.length;
        double ret = 0.0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    ret = Math.max(ret, triangleArea(points[i][0], points[i][1], points[j][0], points[j][1], points[k][0], points[k][1]));
                }
            }
        }
        return ret;
    }

    public double triangleArea(int x1, int y1, int x2, int y2, int x3, int y3) {
        return 0.5 * Math.abs(x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2);
    }
}

当然肯定不应该只用暴力,因为 $O(n^3)$ 再多一点就会爆炸(

凸包

咕咕


25 – 09 – 27 (补于 25 – 10 – 03)

今日份题面

给定由一些正数(代表长度)组成的数组 nums ,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回 0

在边长有序(升序)的情况,由贪心我们很容易想到最大边长一定出现在数组最右侧,此时最长的三条边 a, b, c(a>b>c) 如果不满足 a < (b + c) 那么必定无解

class Solution {
    public int largestPerimeter(int[] nums) {
        Arrays.sort(nums);
        for (int i = nums.length - 1; i >= 2; i--) {
            if (nums[i - 2] + nums[i - 1] > nums[i]) {
                return nums[i - 2] + nums[i - 1] + nums[i];
            }
        }
        return 0; // 无解
    }
}

以上


25 – 09 – 28 (补于 25 – 10 – 04)

今日份题面

你有一个凸的 n 边形,其每个顶点都有一个整数值。给定一个整数数组 values ,其中 values[i] 是第 i 个顶点的值(即 顺时针顺序 )。

假设将多边形 剖分 为 n - 2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 n - 2 个三角形的值之和。

返回 多边形进行三角剖分后可以得到的最低分 。

爆搜吧哎呀

好久不写搜索又忘了…

class Solution {
    public int minScoreTriangulation(int[] values) {
        int l = values.length, numsOflinesLim = l - 3;
        int [][] memo = new int [l][l];
        for(int [] i :memo){
            Arrays.fill(i, -1);
        }
        return dfs(0, l - 1, values, memo);

    }
    private int dfs(int i, int j, int [] values, int [][] memo){
        if(i + 1 == j){
            return 0;
        }
        if(memo[i][j] != -1){
            return memo[i][j];
        }
        int res = Integer.MAX_VALUE;
        for(int k = i + 1; k < j; k++){
            int curRes = dfs(i, k ,values, memo) + dfs(k, j, values, memo) + values[i] * values[j] * values[k];
            res = Math.min(res, curRes);
        }
        return memo[i][j] = res;
    }
}

25 – 09 – 29 (补于 25 – 10 – 05)

今日份题面

给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是 0 到 9 之间(两者都包含)的一个数字。

nums 的 三角和 是执行以下操作以后最后剩下元素的值:

  1. nums 初始包含 n 个元素。如果 n == 1 ,终止 操作。否则,创建 一个新的下标从 0 开始的长度为 n - 1 的整数数组 newNums 。
  2. 对于满足 0 <= i < n - 1 的下标 i ,newNums[i] 赋值 为 (nums[i] + nums[i+1]) % 10 ,% 表示取余运算。
  3. 将 newNums 替换 数组 nums 。
  4. 从步骤 1 开始 重复 整个过程。

请你返回 nums 的三角和。

考虑数组 $[i, j, k]$ ,那么在一次变换后数组为 $[(i + j) % 10, (j + k) % 10]$ ,显然 i 和 k 只用了一次,于是我们可以原地操作,将新生成的结果填充在前一个元素的位置,同时下一次循环的右边界左移一位。

class Solution {
    public int triangularSum(int[] nums) {
        int l = nums.length, res = 0;
        int [] tempNums = new int [l];
        System.arraycopy(nums, 0, tempNums, 0 ,l);        
        for(int i = 1; i < l; ++i){
            for(int j = 0; j < l - i; ++j){
                tempNums[j] = (tempNums[j] + tempNums[j + 1]) % 10;
            }
        }
        return tempNums[0];
    }
}

以上

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注