22年4月刷题总结

伴随着互联网裁员的压力和入职时间的临近,又开始刷每日一题啦
本次只记录每题的要点,不关注具体实现
时间为倒序

4-26 Lc883 三维形体投影面积

  • 俯视图就是判断是否大于0,每个柱子的面积,要么1,要么0
  • 两个侧视图分别是用i和j来遍历数组,面积是分别i和j的最大值
  • 比较简单

4-25 Lc398 随机数索引

  • 这题还是挺有意思的,要返回数组中目标随机数的任意随机一个的索引

  • 如果输入数组不大,可以放到内存中来,而且需要查询的次数较多,那么使用map来存储比较好,这样类生成的时间是O(n),而后面查询的话是O(1)

  • 如果输入的数组比较大,无法放进内存,或者查询的次数较少,那么可以用水塘抽样法,我也是看了题解才知道的

    • 这个思想在于,当找到第一个target时,我们在 [ 0 , 1 ) [0,1) [0,1)之间随机,这个是一定的,然后每找到一个target,我们就用当前的 1 / k 1/k 1/k概率来替代结果,所以分别是 1 , 1 / 2 , 1 / 3 , 1 / 4...1 / k 1,1/2,1/3,1/4...1/k 1,1/2,1/3,1/4...1/k,所以任意一个target索引被选中的概率就是 p = 1 / i ∗ i / i + 1 + . . . k / k + 1 = 1 / k p=1/i * i/i+1 +... k/k+1=1/k p=1/ii/i+1+...k/k+1=1/k,最终结果就是 1 / k 1/k 1/k
    • 这里需要注意,第i个被选中的概率,是不与前面的target相关的,值与后面的影响
    • 这个有点神奇,数学的魅力嘛,反正记下来,没见过基本就不会,谁能想到证明这个…
  • 除此之外,水塘抽样,可以解决O(n)内,O(1)空间的目标随机抽样问题,该题确实有点意思

4-24 Lc868 二进制间距

  • 没啥意思,不赘述

4-23 Lc587 安装栅栏

  • 凸包问题
  • Graham方法
  • 核心点在于,寻找第一个凸点,然后按照角度来遍历, 每两条边的凸出方向一定是向外的,这个通过两条边向量的角度来判断,每次两条边来找凸,从而最终找出凸包边界

4-22 Lc396 旋转函数

  • 说实话做完这题,我还是没弄懂它这个旋转是啥意思,形容有点莫名其妙
  • 观察示例,其实可以发现f(0)和f(1)之间是有雪薇的差距的,除了nums中的某个数,其他所有数都是增加了一个,而那个数,则是减少了n个
  • 发现了这个规律,就可以O(n)解出这题了
    在这里插入图片描述
  • 代码也很好写了
class Solution {
   public int maxRotateFunction(int[] nums) {
       int n = nums.length, sum = 0, f = 0;
       for(int i=0;i<nums.length;i++){
           sum += nums[i];
           f += i*nums[i];
       }
       int res = f;
       for(int i=nums.length-1;i>0;i--){
           f += sum - n*nums[i];
           res = Math.max(res,f);
       }
       return res;
   }
}

4-21 Lcxxx

  • 这题太简单,没必要赘述

4-20 Lc388 文件的最长绝对路径

  • 这题最坑的地方在于输入中\n是换行符,而不是字符,而\t也是一样,因此不能当做字符来对待它们,这也导致我花了很长时间弄这个
  • 输入已经是dfs的顺序了,所以需要记录上一层的长度,
  • 使用栈来进行模拟,栈中元素为 [ 当 前 层 数 , 前 一 层 长 度 , 当 前 目 录 长 度 ] [当前层数,前一层长度,当前目录长度] [,,]
  • 出栈条件:当前层数<栈顶层数
  • 入栈条件:当前层数>=栈顶层数,当前不是文件而是文件夹
  • 然后需要注意对文件进行判断,通过 . . .进行判断
class Solution {
    //首先通过\n来把不同的名称分开
    //建立栈,栈中元素为[x,x,x],分别为层数,上一层长度,本名称长度
    //遍历名称,如果当前的层数比栈顶大于等于,则将当前入栈
    //如果栈顶层数小于等于自己,则弹出为止
    //如果当前的名称为文件,那么不可能有下一层,那么就不如栈,即栈里只放文件夹,不放文件
    public int lengthLongestPath(String input) {
        Stack<int[]> stack = new Stack<>();
        String[] ss = input.split("\n");
        int len = 0;
        for(int i=0;i<ss.length;i++){
            int[] curInfo = parse(ss[i]);
            while(!stack.isEmpty()&&curInfo[0]<stack.peek()[0]) stack.pop();
            int preLen = stack.isEmpty()?0:stack.peek()[1];
            preLen += stack.isEmpty()||stack.peek()[0]==curInfo[0]?0:stack.peek()[2];
            //相同层次时,就不用相加了
            if(curInfo[2]==1) len = Math.max(curInfo[1]+preLen,len); // 文件
            else stack.push(new int[]{curInfo[0],preLen,curInfo[1]});//目录
        }
        return len;
    }
    private int[] parse(String s){
        int level = s.lastIndexOf("\t")+1;//层数
        int isFile = s.contains(".")?1:0;//判断是否是文件
        int len = s.length() - level + (level>0?1:0);//补齐/的字符长度
        return new int[]{level,len,isFile};
    }
}

4-19 Lc821 字符的最短距离

  • 求字符串中每个字符到目标字符的最短距离,字符串中可能含有多个目标字符
  • 可以O(n)求解
  • 正向一遍,找到每个字符右边的最近目标字符
  • 反向一遍,找到每个字符左边的最近目标字符
  • 取最小值,即可完成

4-18 Lc386 字典序排数

  • 1 − n 1-n 1n进行字典序排序
  • 思路是通过dfs来生成,模拟字典序
  • 逻辑为:
dfs(num):
	如果(num<=n),添加
	dfs(num*10)
	如果num+1不产生进位,dfs(num+1)
  • 核心在于+1不能产生进位,否则会与*10的结果重复

4-17 Lc819 最常见的单词

  • 核心在于,如何对一段英文进行分词
String[] ss = paragraph.toLowerCase().split("[ !?',;.]");
  • 当然,这会产生空格字符串,所以在后面就直接continue"" 即可

4-16 Lc479 最大回文数乘积

  • 本题是将范围内的回文数分解成两个数的乘积,要求最大
  • 思路是从大到小,挨个生成回文数,然后看能不能分解
  • 核心在于回文数的生成,整体逻辑也需要注意
回文数: 123321 轴对称
那么实际可以由 123生成,p(123) = 123*1000 + rev(123) = 123 321
其中rev为翻转,reverse
那么该比该回文数小的下一个回文数是 122 221 = 122*1000 + rev(122) = p(122)
即只需要对123进行p()操作即可
因此我们从一开始就可以用99XX来生成回文数
至于分解,就从9X开始,一个个除,能除尽为止,一旦因子的平方也小于回文数时,就剪枝返回

4-15 Lc385 迷你语法分析器

  • 这题我用的递归做的,挺麻烦,用栈会相对简单一点
  • 没啥好说的,挺经典的题,但是题目要求使用的数据结构真是让我想吐芬芳,你大爷,比宫崎英高都恶心

4-14 Lc1672 最富有客户的总资产

  • 太简单了,力扣要亡

4-13 Lc380 O(1)时间插入 删除 和获取

  • 需要设计数据结构set来保证O(1)时间xxx
  • 难点在于等概率随机获取,一般想到实现就是在 [ 1 , n ] [1,n] [1,n]之间生成随机数,通过索引来获取,此时就可以是O(1)的
  • 核心在于,通过一个map和数组实现,删除的实现尤为关键,需要保证索引的连续
map中存放 num-index
数组中存放num
二者相对应
当插入时,同时更新map和数组
当获取随机时,生成数组容量的随机数,返回
当删除时,将数组的最后一个数与被删除的数交换,保证索引的连续,然后更新map
  • 本题的进阶为381应该是,随机的概率是线性的,可以重复插入,这个也很简单
  • 直接把map中 num-index换成 num-indexs:List 即可,当可以重复插入时,本身随机就是线性的

4-12 Lc806 写字符串需要的行数

  • 这题也简单,就是整个词不能跨行,所以就用剩余的空间与当前词比较,不行的话就将剩余空间重置为一整行
  • 感觉有点像是内存空间放对象一样

4-11 Lc357 统计各位数字都不同的数字个数

  • 这题还是不错的
  • 首先对于n=5的情况,当xxxxx中第一个x为0时,其实这就是f(4)的结果,所以这有个递归的过程
  • 而对于第一个x不为0时,此时有多少种可能,这就成了高中学过的概率问题,第一个x有1-9 9种可能,第二个x可以为0,它与第一个不同,所以也有9种可能,第三个x有8种可能,第四个7…
  • 实现起来很简单,想也不是那么难想,但确实有趣,可以扩展思路

4-10 Lc804 唯一摩尔斯密码词

  • 纯属浪费时间

4-9 Lc780 到达终点

  • 核心在于,从起点到终点,每一步都会有两个选择,而从终点到起点,实际上每次只有一个选择,所以倒着来是本题的关键
  • 从终点出发,每次通过横纵坐标的减法减小
  • 会出现,横纵坐标差距过大,导致时间复杂度太大的问题,所以做减法时,需要尽可能的多减一点,但是又不能减到结果小于起点,所以这里得稍微麻烦一点

先记到这,这个月是月初开始写的,写到今天也有半个月了,全部记完也没啥意义

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值