386. 字典序排数 / 剑指 Offer II 009. 乘积小于 K 的子数组

386. 字典序排数【中等题】【每日一题】

思路:

由题意知共有n个数,所以要在集合中添加n个数据,因此添加数据过程需要一个for循环。
从1开始按字典序添加所有小于n的数,那么第一个添加1,第二个添加以1开头的小于等于n的极限值a,然后在这个极限值下慢慢自增1,并将自增后的值添加到列表中,直到逼近n,然后将极限值a缩小10倍,成为极限值b,继续自增1并将自增后的值添加到列表中,直到当前这个极限值b位数填满,然后将极限值b缩小10倍,成为极限值c,继续自增1并将自增后的值添加到列表中,…
直到操作n遍之后循环正常结束。

代码:

class Solution {
    public List<Integer> lexicalOrder(int n) {
        List<Integer> ans = new ArrayList<>();
        //i 为遍历次数,由于数据范围为[i,n],因此共需在ans中添加 n 遍数据
        //j 为当前要添加的数,j从1开始
        for (int i = 0,j = 1; i < n; i++) {
            ans.add(j);//将当前这个j添加到ans列表中
            if (j * 10 <= n){//判断 j 的 10倍是否在数据范围内,如果在,则下一个字典序数字至少应为 j 的10倍
                j *= 10;
            }else {//如果 j的10倍不在数据范围内,说明以某个数开头的数的字典序找到边界了,边界就是[j,n],比如说示例中的 n= 13,那么j=10时,10*10 = 100 > 13,所以边界在[10,13]
                //找到边界之后
                // j + 1 > n ? 判断 j是否就是 n,比如说n=13,j=13,那此时肯定要从 1 开始遍历j,因为如果不先将j缩小10倍必然会导致数据越界
                // j % 10 == 9 ? 判断 j是否是当前位数的极限,比如说 n=20,j = 19,那此时肯定要从 2 开始遍历j,因为如果不先将j缩小10倍必然会导致数据的丢失(会丢失数据2)
                // 如果是,那么就没有j++递增的必要了,需要将 j /= 10缩小10倍之后再遍历 j
                while (j % 10 == 9 || j+1 > n){
                    j /= 10;
                }
                j++;
            }
        }
        return ans;
    }
}

剑指 Offer II 009. 乘积小于 K 的子数组【中等题】

思路:

与昨天的题目 剑指 Offer II 008. 和大于等于 target 的最短子数组
思路类似,采用滑动窗口动态更新子数组的左右端点和乘积。
需要注意的是本题让统计的是乘积小于k的子数组的个数,经过观察发现当一个子数组满足题意时,它为整个子数组贡献的子数组个数子数组窗口的宽度在数值上是相等的,因此设计出以下代码。

代码:

class Solution {
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        int start = 0,end = 0,len = nums.length;
        int ans = 0,ji = 1;
        while (end < len){
            ji *= nums[end];//累乘ji
            ans += end-start+1;//统计乘积小于k的子数组个数
            while (ji >= k && start <= end){
                ji /= nums[start++];//乘积大于k,需要将区间起始位置除去,并更新区间起始位置
                ans--;//多加了一种可能,需要将其减掉
            }
            end++;//更新区间结束位置
        }
        return ans;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值