月度归档: 2021年10月

LeetCode刷题【273】整数转换英文表示

将非负整数 num 转换为其对应的英文表示。

 

示例 1:

输入:num = 123
输出:"One Hundred Twenty Three"

示例 2:

输入:num = 12345
输出:"Twelve Thousand Three Hundred Forty Five"

示例 3:

输入:num = 1234567
输出:"One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"

示例 4:

输入:num = 1234567891
输出:"One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One"

 

提示:

  • 0 <= num <= 231 - 1
Related Topics
  • 递归
  • 数学
  • 字符串

  • 👍 177
  • 👎 0
  • 今天每日一题

    随便写下
    一个需要知道的基本知识点,英文和中文中的差别
    中文中可以理解为4位一段,

    从个到千
    从万到千万
    从亿到千亿
    但是英文中不是这样的,英文中是按照3位一段的计数法,比如例子
    1234567891,我们有某些时候看到的表达方式是这样的
    1 , 234 , 567 , 891

    7 Thousand
    4 Million
    1 Billion
    对于小于3位的部分,就很简单了,就是 X hundred XX这样的结构

    那么思路就是这样的了

    1. 每3位处理一次,这样每次除以1000取余来处理这部分数据,然后再处理除以1000之后取整的数字
    2. 百位直接按1-9取英文再加Hundred,如果没有百位,则跳过
    3. 100以下的部分,1-19单独处理,大于等于20的,按照整10部分+个位数部分处理转换

    class Solution {
        public String numberToWords(int num) {
            if (num ==0){
                return "Zero";
            }
            String[] arr1 = new String[]{"","Thousand","Million","Billion"};
            String[] arr2 = new String[]{"Hundred"};
            String[] arr3 = new String[]{"","One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
            String[] arr4 = new String[]{"Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};
            String[] arr5 = new String[]{"","","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
            int idx1 = 0;
            ArrayList<String> list = new ArrayList<>();
            while (num != 0){
                int tmp = num % 1000;
                num = num / 1000;
                int hundred = tmp / 100;
                tmp = tmp % 100;
                StringBuffer sb2 = new StringBuffer();
                if (hundred>0){
    //                System.out.print(arr3[hundred]+" "+arr2[0]+" ");
                    sb2.append(arr3[hundred]).append(" ").append(arr2[0]).append(" ");
                }
                if (tmp>=20){
    //                System.out.print(arr5[tmp/10] + " " + arr3[tmp%10] + " ");
                    sb2.append(arr5[tmp/10]).append(" ");
                    if (tmp%10>0){
                        sb2.append(arr3[tmp%10]).append(" ");
                    }
                }else if (tmp < 10 && tmp > 0){
    //                System.out.print(arr3[tmp%10] + " ");
                    sb2.append(arr3[tmp%10]).append(" ");
                }else if (tmp>0){
    //                System.out.print(arr4[tmp-10] + " ");
                    sb2.append(arr4[tmp-10]).append(" ");
                }
    //            System.out.println(arr1[idx1]);
                if (sb2.length()>0){
                    sb2.append(arr1[idx1]).append(" ");
                }
                idx1++;
                list.add(0,sb2.toString());
            }
            StringBuffer sb = new StringBuffer();
            for (String s : list) {
    //            System.out.println(s);
                sb.append(s);
            }
            String a = sb.toString();
            while (a.charAt(a.length()-1) == ' '){
                a = a.substring(0,a.length()-1);
            }
            return a;
        }
    }

    拓展小知识来源百度
    1至10无规律可循: one、two、three、four、five、six、seven、eight、nine、ten;
    11至19 :eleven、twelve、thirteen、fourteen、fifteen、sixteen、seventeen、eighteen、 nineteen;
    从20至99:整数的几十中除了twenty(二十)、thirty(三十)、forty(四十)、fifty(五十)、eighty(八十)为特殊形式外,sixty(六十)、seventy(七十)、ninety(九十)都是其个位数形式后添加后缀-ty构成。
    百位数个数基数词形式加“hundred”,表示几百,在几十几与百位间加上and。
    第四条一般认为是英式表达中会用到,本题中都没有and,一开始做的时候感觉有点怪怪的
    另外还有一些其他的细节性的表达,比如2000这种的结尾加only表示整。

    LeetCode刷题【42】接雨水(动态规划)

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

     

    示例 1:

    输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
    输出:6
    解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 
    

    示例 2:

    输入:height = [4,2,0,3,2,5]
    输出:9
    

     

    提示:

    • n == height.length
    • 0 <= n <= 3 * 104
    • 0 <= height[i] <= 105
    Related Topics
  • 数组
  • 双指针
  • 动态规划
  • 单调栈
  • \n
  • 👍 2503
  • 👎 0
  • 刷动态规划重新做到这一题,之前写的是基于单调队列的,可以看下之前的文章,LeetCode刷题【42】接雨水

    重新审视下这题,某个位置能存储的最大雨量依赖于他的左侧的最大值和他右侧的最大值这两个值中的较小的一个值。那么怎么取到左侧的最大值和右侧的最大值呢?

    • 从左往右依次比较保存最大值就是某个位置的左侧的最大值
    • 从右往左依次比较保存最大值就是某个位置右侧的最大值

    在这样的情况下,我们建立一个二维数组,dp[i][2],其中dp[i][0]表示该位置左侧的最大值,dp[i][1]表示该位置右侧的最大值。这样对应的i位置能存储的最大水量就是

    min(dp[i][0],dp[i][1])-height[i]

    转移方程已经确定的情况下那么代码也就非常容易写出来了

    class Solution {
        public int trap(int[] height) {
            int count = 0;
            int[][] dp = new int[height.length][2];
            int idxLeft = 0;
            int idxRight = height.length - 1;
    
            dp[idxLeft][0] = height[idxLeft];
            dp[idxRight][1] = height[idxRight];
            idxLeft++;
            idxRight--;
            for (; idxLeft < height.length; idxLeft++) {
                dp[idxLeft][0] = Math.max(dp[idxLeft-1][0],height[idxLeft]);
                dp[idxRight][1] = Math.max(dp[idxRight+1][1],height[idxRight]);
                if (idxLeft>=idxRight){
                    count += Math.min(dp[idxLeft][0],dp[idxLeft][1]) - height[idxLeft];
                    count += Math.min(dp[idxRight][0],dp[idxRight][1]) - height[idxRight];
                }
                idxRight--;
            }
            if (height.length%2==1){
                int mid = height.length >> 1;
                count -= Math.min(dp[mid][0],dp[mid][1]) - height[mid];
            }
            return count;
        }
    }

    这段代码,在一次遍历的过程中同时更新左侧的最大值和右侧的最大值,当两侧往中间靠拢的时候,如果在中间相遇了,那么就可以开始统计了。

    后面有一段如果height数组长度为基数,中间值会重复计算一遍所以需要减去

    LeetCode刷题【187】重复的DNA序列

    所有 DNA 都由一系列缩写为 'A''C''G''T' 的核苷酸组成,例如:"ACGAATTCCG"。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。

    编写一个函数来找出所有目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。

     

    示例 1:

    输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"
    输出:["AAAAACCCCC","CCCCCAAAAA"]
    

    示例 2:

    输入:s = "AAAAAAAAAAAAA"
    输出:["AAAAAAAAAA"]
    

     

    提示:

    • 0 <= s.length <= 105
    • s[i]'A''C''G''T'
    Related Topics
  • 位运算
  • 哈希表
  • 字符串
  • 滑动窗口
  • 哈希函数
  • 滚动哈希

  • 👍 232
  • 👎 0
  • 每日一题。简单做下。哈希表暴力枚举

    class Solution {
        public List<String> findRepeatedDnaSequences(String s) {
            HashSet<String> set = new HashSet<>();
            HashSet<String> set2 = new HashSet<>();
            char[] tmp = new char[10];
            char[] chars = s.toCharArray();
            int i = 0;
            int length = s.length() - 10;
            for (; i <= length; i++) {
                System.arraycopy(chars,i,tmp,0,10);
                String tmpStr = new String(tmp);
                if (set.contains(tmpStr)){
                    set2.add(tmpStr);
                }else {
                    set.add(tmpStr);
                }
            }
            return new ArrayList<>(set2);
        }
    }

    挨个构建长度为10的字符串塞入set中,如果在塞入之前已经存在,则说明已经存在过,则塞入set2中,这样保证了set2中都是至少出现过两次的的字符串。

    最终返回set2集合。

    LeetCode刷题【376】摆动序列

    如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

    • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

    • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

    子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

    给你一个整数数组 nums ,返回 nums 中作为 摆动序列 最长子序列的长度

     

    示例 1:

    输入:nums = [1,7,4,9,2,5]
    输出:6
    解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
    

    示例 2:

    输入:nums = [1,17,5,10,13,15,10,5,16,8]
    输出:7
    解释:这个序列包含几个长度为 7 摆动序列。
    其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
    

    示例 3:

    输入:nums = [1,2,3,4,5,6,7,8,9]
    输出:2
    

     

    提示:

    • 1 <= nums.length <= 1000
    • 0 <= nums[i] <= 1000

     

    进阶:你能否用 O(n) 时间复杂度完成此题?

    Related Topics
  • 贪心
  • 数组
  • 动态规划

  • 👍 515
  • 👎 0
  • 先上代码

    class Solution {
        /**
         * 输入:nums = [1,17,5,10,13,15,10,5,16,8]
         *          1, 17,  5, 10, 13, 15, 10,  5, 16,  8
         *             升   降  升  升  升   降   降  升  降
         *  降序结尾 0  0   2   2   2   2   4    4   4   6
         *  升序结尾 0  1   1   3   3   3   3    5   5   5
         *  if 升 {
         *     dp[i][降] = dp[i-1][降]
         *     dp[i][升] = dp[i-1][降]+1
         *  }
         *  if 降{
         *      dp[i][降] = dp[i-1][升]+1
         *      dp[i][升] = dp[i-1][升]
         *  }
         *
         * @param nums
         * @return
         */
        public int wiggleMaxLength(int[] nums) {
            int[][] dp = new int[nums.length][2];
            int i = 1;
            for (; i < nums.length; i++) {
                //dp[i][0]降序结尾
                //dp[i][1]升序结尾
                if (nums[i] > nums[i-1]){
                    dp[i][0] = dp[i-1][0];
                    dp[i][1] = dp[i-1][0]+1;
                }else if (nums[i] < nums[i-1]){
                    dp[i][0] = dp[i-1][1]+1;
                    dp[i][1] = dp[i-1][1];
                }else{
                    //相等
                    dp[i][0] = dp[i-1][0];
                    dp[i][1] = dp[i-1][1];
                }
            }
            return Math.max(dp[--i][0],dp[i][1])+1;
        }
    }

    当我们分析的时候,假设当前在第i位置,如果想要能追加到前面的摆动序列的结尾,那么我们需要知道一个事情,之前的这摆动序列的结尾是升序还是降序的
    这样的情况下,我们建立了2维dp数组

    • dp[i][0]表示,到当前位置,以降序结尾的摆动数组的最长子序列的长度
    • dp[i][1]表示,到当前位置,以升序结尾的摆动数组的最长子序列的长度
    • 所以如果当前是升序的话,则当前位置的升序结尾的最长子序列的长度可以由之前的降序最长子序列的长度加1,此时的降序继续继承前一个状态的长度。
    • 若当前是降序同理
    • 最终以为我们统计的实际是能追加的个数,需要在结果上再加1表示加上一开始初始的节点个数

    至于更进一步的dp[i]数组转化为两个变量的写法就省略不写了,我们可以很明白的看到dp[i]的状态只依赖于dp[i-1]这样就可以直接用两个变量代替原来的dp[i]数组,这里写作数组的形式只是为了更加便于理解动态规划方法的实现原理

    LeetCode刷题【309】最佳买卖股票时机含冷冻期

    给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

    设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

    • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
    • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

    示例:

    输入: [1,2,3,0,2]
    输出: 3 
    解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
    Related Topics
  • 数组
  • 动态规划

  • 👍 912
  • 👎 0
  • class Solution {
        public int maxProfit(int[] prices) {
            int[][] dp = new int[prices.length][3];
            dp[0][0] = -prices[0];
            int i = 1;
            for (; i < prices.length; i++) {
                //0 持有
                dp[i][0] = Math.max(dp[i-1][1]-prices[i], dp[i-1][0]);
                //1 不持有,不在冷冻期
                dp[i][1] = Math.max(dp[i-1][2], dp[i-1][1]);
                //2 不持有,在冷冻期
                dp[i][2] = dp[i-1][0]+prices[i];
    
            }
            return Math.max(dp[--i][1],dp[i][2]);
        }
    }

    参考