LeetCode Weekly Contest 177

日期之间隔几天

请你编写一个程序来计算两个日期之间隔了多少天。

日期以字符串形式给出,格式为 YYYY-MM-DD,如示例所示。

示例 1:

输入:date1 = “2019-06-29”, date2 = “2019-06-30”
输出:1
示例 2:

输入:date1 = “2020-01-15”, date2 = “2019-12-31”
输出:15

提示:

给定的日期是 1971 年到 2100 年之间的有效日期。

思路

超级经典的模拟题。关键在于提取公共部分写成函数,不要让思维淹没在for-if-else的海洋里。

代码

class Solution {
    private static final int[] Months = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    private boolean runNian(int year) {
        if (year % 400 == 0) {
            return true;
        }
        if (year % 100 == 0) {
            return false;
        }
        if (year % 4 == 0) {
            return true;
        } else {
            return false;
        }
    }
    
    private int fromYearBegin(int year, int month, int day) {
        int i = 0, ret = 0;
        for (i=0; i<month-1; ++i) {
            ret += (i==1 && runNian(year))? Months[i] + 1: Months[i];
        }
        return ret + day;
    }
    
    public int daysBetweenDates(String date1, String date2) {
        int i = 0, ret = 0;
        if (date1.compareTo(date2) < 0) {
            String tmp = date1;
            date1 = date2;
            date2 = tmp;
        }
        String[] fields = date1.split("-");
        int y1 = Integer.parseInt(fields[0]), m1 = Integer.parseInt(fields[1]), d1 = Integer.parseInt(fields[2]);
        fields = date2.split("-");
        int y2 = Integer.parseInt(fields[0]), m2 = Integer.parseInt(fields[1]), d2 = Integer.parseInt(fields[2]);
        for (i=y2; i<y1; ++i) {
            ret += runNian(i)? 366: 365;
        }
        ret += fromYearBegin(y1, m1, d1) - fromYearBegin(y2, m2, d2);
        return ret;
    }
}

验证二叉树

二叉树上有 n 个节点,按从 0 到 n - 1 编号,其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。

只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时,返回 true;否则返回 false。

如果节点 i 没有左子节点,那么 leftChild[i] 就等于 -1。右子节点也符合该规则。

注意:节点没有值,本问题中仅仅使用节点编号。
示例 1:

输入:n = 4, leftChild = [1,-1,3,-1], rightChild = [2,-1,-1,-1]
输出:true
示例 2:

输入:n = 4, leftChild = [1,-1,3,-1], rightChild = [2,3,-1,-1]
输出:false
示例 3:

输入:n = 2, leftChild = [1,0], rightChild = [-1,-1]
输出:false
示例 4:

输入:n = 6, leftChild = [1,-1,-1,4,-1,-1], rightChild = [2,-1,-1,5,-1,-1]
输出:false

提示:

1 <= n <= 10^4
leftChild.length == rightChild.length == n
-1 <= leftChild[i], rightChild[i] <= n - 1

思路

按照『树』的定义,递归判断是否有环以及是否连通

代码

class Solution {
    private int dfs(int s, boolean[] vis, int[] left, int[] right) {
        vis[s] = true;
        int ret = 1;
        if (left[s] != -1) {
            if (vis[left[s]]) {
                return -1;
            }
            ret += dfs(left[s], vis, left, right);
        }
        if (right[s] != -1) {
            if (vis[right[s]]) {
                return -1;
            }
            ret += dfs(right[s], vis, left, right);
        }
        return ret;
    }
    
    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
        boolean[] vis = new boolean[n];
        return dfs(0, vis, leftChild, rightChild) == n;
    }
}

最接近的因数

给你一个整数 num,请你找出同时满足下面全部要求的两个整数:

两数乘积等于 num + 1 或 num + 2
以绝对差进行度量,两数大小最接近
你可以按任意顺序返回这两个整数。

示例 1:

输入:num = 8
输出:[3,3]
解释:对于 num + 1 = 9,最接近的两个因数是 3 & 3;对于 num + 2 = 10, 最接近的两个因数是 2 & 5,因此返回 3 & 3 。
示例 2:

输入:num = 123
输出:[5,25]
示例 3:

输入:num = 999
输出:[40,25]

提示:

1 <= num <= 10^9

代码

class Solution {
    private int[] divide(int num) {
        int[] ret = new int[2];
        for (int i=(int)Math.sqrt(num); i>=1; --i) {
            if (num % i == 0) {
                ret[0] = i;
                ret[1] = num / i;
                break;
            }
        }
        return ret;
    }
    
    public int[] closestDivisors(int num) {
        int[] div1 = divide(num + 1), div2 = divide(num + 2);
        if (Math.abs(div1[0] - div1[1]) < Math.abs(div2[0] - div2[1])) {
            return div1;
        } else {
            return div2;
        }
    }
}

形成三的最大倍数

给你一个整数数组 digits,你可以通过按任意顺序连接其中某些数字来形成 3 的倍数,请你返回所能得到的最大的 3 的倍数。

由于答案可能不在整数数据类型范围内,请以字符串形式返回答案。

如果无法得到答案,请返回一个空字符串。

示例 1:

输入:digits = [8,1,9]
输出:“981”
示例 2:

输入:digits = [8,6,7,1,0]
输出:“8760”
示例 3:

输入:digits = [1]
输出:""
示例 4:

输入:digits = [0,0,0,0,0,0]
输出:“0”

提示:

1 <= digits.length <= 10^4
0 <= digits[i] <= 9
返回的结果不应包含不必要的前导零。

思路

注意到3的倍数的特点是各位相加也是3的倍数。另外注意去掉前导零。

代码

class Solution {
    private String toZero(String num) {
        if (num.length() > 0 && num.charAt(0) == '0') {
            return "0";
        } else {
            return num;
        }
    }
    
    public String largestMultipleOfThree(int[] digits) {
        if (digits.length == 0) {
            return "";
        }
        int sum = 0, n = digits.length, i = 0;
        StringBuilder sb = new StringBuilder();
        Arrays.sort(digits);
        for (int dig: digits) {
            sum += dig;
        }
        if (sum % 3 == 0) {
            for (i=n-1; i>=0; --i) {
                sb.append(digits[i]);
            }
            return toZero(sb.toString());
        }
        int minMod1 = Integer.MAX_VALUE, minIdx1 = -1, secMod1 = Integer.MAX_VALUE, minMod2 = Integer.MAX_VALUE, secMod2 = Integer.MAX_VALUE, minIdx2 = -1;
        int idx = 0;
        for (int dig: digits) {
            if (dig % 3 == 1 && dig < minMod1) {
                minMod1 = dig;
                minIdx1 = idx;
            }
            if (dig % 3 == 2 && dig < minMod2) {
                minMod2 = dig;
                minIdx2 = idx;
            }
            ++idx;
        }
        idx = 0;
        for (int dig: digits) {
            if (dig % 3 == 1 && dig < secMod1 && idx != minIdx1) {
                secMod1 = dig;
            }
            if (dig % 3 == 2 && dig < secMod2 && idx != minIdx2) {
                secMod2 = dig;
            }
            ++idx;
        }
        int flag = 0;
        if (sum % 3 == 1) {
            if (minMod1 != Integer.MAX_VALUE) {
                flag = 0;
                 for (i=n-1; i>=0; --i) {
                     if (flag == 0 && digits[i] == minMod1) {
                         ++flag;
                     } else {
                         sb.append(digits[i]);
                     }
                 }       
            } else {
                flag = 0;
                for (i=n-1; i>=0; --i) {
                    if (flag < 2) {
                        if (digits[i] == minMod2 || digits[i] == secMod2) {
                            ++flag;
                        } else {
                            sb.append(digits[i]);
                        }
                    } else {
                        sb.append(digits[i]);
                    }
                 }  
            }
        } else {
            if (minMod2 != Integer.MAX_VALUE) {
                flag = 0;
                 for (i=n-1; i>=0; --i) {
                     if (flag == 0 && digits[i] == minMod2) {
                         ++flag;
                     } else {
                         sb.append(digits[i]);
                     }
                 }       
            } else {
                flag = 0;
                for (i=n-1; i>=0; --i) {
                    if (flag < 2) {
                        if (digits[i] == minMod1 || digits[i] == secMod1) {
                            ++flag;
                        } else {
                            sb.append(digits[i]);
                        }
                    } else {
                        sb.append(digits[i]);
                    }
                 }  
            }
        }
        return toZero(sb.toString());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值