leetcodeTmp

文章目录

      • 39. 组合总和
      • 33. 搜索旋转排序数组
      • 153. 寻找旋转排序数组中的最小值
      • 49. 字母异位词分组
      • 53. 最大子数组和
      • 55. 跳跃游戏
      • 56. 合并区间
      • 62. 不同路径

39. 组合总和

39. 组合总和

DFS排列:每个元素可选0次,1次以及多次

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    //Arrays.sort(candidates);//注释了也能通过
    this.candidates = candidates;
    ans.clear();
    comb(0,target,new ArrayList<Integer>());
    return ans;
}

int[] candidates;
List<List<Integer>> ans = new ArrayList<>();
void comb(int k,int target,List<Integer> nums){

    if(target==0){
        ans.add(nums);
        return;
    }

    // target后判断
    if(k>=candidates.length) return;

    //不选
    comb(k+1,target,nums);

    // 选一个或者多个
    int t = target;
    List<Integer> numst = new ArrayList<Integer>(nums);
    while (t-candidates[k]>=0){
        t -= candidates[k];// 本结点可以选多次
        numst.add(candidates[k]);
        comb(k+1,t,numst);
    }
}

33. 搜索旋转排序数组

33. 搜索旋转排序数组

难点在于logN的时间复杂度

旋转之后的数据分为两个分别升序的部分,若能找到分割点(原来的a[0])那么在两部分分别进行两次二分查找,不就logN了

这个时候难点就在找分割点了,旋转次数是未知的,分割点也就未知,还得最高logN找分割点,这个时候题目转换成另外一个问题了。

153. 寻找旋转排序数组中的最小值

做完下面的153,再来做本题,就很简单了。

public int search(int[] nums, int target) {
    int min = findMin(nums),low=0,high=nums.length-1;
    if(target>nums[high]) high = min-1; //左边
    else  low = min;

    // 接下来 low和high里二分查找即可
    while (low<=high){//加等号 可能正好相遇时相等呢
        int mid = (low+high)/2;
        if(nums[mid]==target) return mid;
        else if(nums[mid]<target) low = mid+1;
        else high = mid-1;
    }
    return -1;

}

// 153. 寻找旋转排序数组中的最小值 改成返回最小值下标
public int findMin(int[] nums) {
    int low=0,high=nums.length-1;
    while (low<high){ // 区间长度为1时结束二分
        int mid = (low+high)/2;
        if(nums[mid]>nums[high]) low = mid+1; //改成+1 low右偏,一定在high相遇
        else high = mid;
        // 元素互不相同 不会出现相等的情况
    }
    return high;
}

接下来不找中点,直接用找中点 时nums[high]的性质,判断是在左半段还是右半段,其实用nums[0]也可以判断出来,就用nums[0]吧,target>nums[0] 一定左半段 target<nums[0] 一定在右半段,相等就直接找到了。 其实就是两个方法合二为一了

  • 利用性质直接二分

还是二分,但是每次判断3点

  1. nums[mid]和target 谁大 taregt小,下标变化要舍弃nums里一些偏大的元素, 否则舍弃nums里比较小的元素
  2. target在左边还是右边 =》 根据target和nums[0]大小可以判断 这会影响舍弃元素时下标变化的策略
  3. mid 在左边还是右边 =》 根据mid 和nums[0]大小可以判断 这会影响舍弃元素时下标变化的策略

合起来一共23-2 = 6 种情况 。 舍弃的两种是:

  1. nums[mid]<target<nums[0] : 也就是不会出现 nums[mid]<target,target右边时(target<nums[0]) ,mid在左边(mid>nums[0])
  2. nums[mid]>target>nums[0] : 也就是不会出现 nums[mid]>target,target左边时(target>nums[0]) ,mid在右边(mid<nums[0])

153. 寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值

不会,直接看题解,真的简单啊。简单分析一下,就会发现,

在这里插入图片描述
nums[high]有一个非常美的性质,取一个元素t, 若t<nums[high],一定在右半段,若t>nums[high],则一定在左半段。 中点 mid = (low+high)/2 ,中点值 nums[mid]必然也满足这个性质。
(“给你一个元素值 互不相同 的数组 nums” 数组元素互不相同

mid在右半段,去掉其右边的:
在这里插入图片描述
mid在左半段,去掉其左边的:
在这里插入图片描述

边界就自己举2个例子,一奇一偶,分别手算看看即可。初步分析,因为high在右边小的部分,

  • 当然最简单的思路,最终只剩下两个元素时退出二分,取小的一个即可
public int findMin(int[] nums) {
    int low=0,high=nums.length-1;
    while (high-low>1){ // 区间长度为1时结束二分
        int mid = (low+high)/2;
        if(nums[mid]>nums[high]) low = mid;
        else high = mid;
        // 元素互不相同 不会出现相等的情况
    }
    return Math.min(nums[low],nums[high]); // 最后剩下两个 取一个最小的即可
}

真的要这么麻烦吗,为何要最后两个取最小,因为 mid = (low+high)/2 左偏了,最后一大一小时 会偏向小下标(大值)。而原本就有序时,左偏又是正确的。

那么让一大一小时,mid右偏不就行了,往右偏,最终相遇点一定偏小,(原本有序,肯定nums[0]相遇)

  • mid = (low+high)/2+1 右偏即可
 public int findMin(int[] nums) {
     int low=0,high=nums.length-1;
     while (low<high){ // 区间长度为1时结束二分
         int mid = (low+high)/2;
         if(nums[mid]>nums[high]) low = mid+1; //改成+1 low右偏,一定在high相遇
         else high = mid;
         // 元素互不相同 不会出现相等的情况
     }
     return nums[high];
 }

2022年09月07日 17:47:32

49. 字母异位词分组

49. 字母异位词分组

太水了,直接暴力也能过:

Map<String,List<String>> mp = new HashMap<String,List<String>>();

public List<List<String>> groupAnagrams(String[] strs) {
    for (String str : strs) {
        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        String key = new String(chars);
        if(mp.containsKey(key)){
            mp.get(key).add(str);
        }else {
            ArrayList<String> list = new ArrayList<>();
            list.add(str);
            mp.put(key,list);
        }
    }

    List<List<String>> ans = new ArrayList<>();
    for (String s : mp.keySet()) {
        ans.add(mp.get(s));
    }

    return ans;
}

看了题解,跟我写法一样,但是人家代码写得比我清爽多了:

map.getOrDefault(getOrDefault(key, default)如果存在key, 则返回其对应的value, 否则返回给定的默认值default)

public List<List<String>> groupAnagrams(String[] strs) {
    Map<String,List<String>> mp = new HashMap<String,List<String>>();
    for (String str : strs) {
        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        String key = new String(chars);
        List<String> list = mp.getOrDefault(key, new ArrayList<String>());
        list.add(str);
        mp.put(key,list);//无则添加 有则覆盖 就是Hash表
    }
    return new ArrayList<>(mp.values());
}

53. 最大子数组和

53. 最大子数组和

简单DP,但是长时间不写,还是生疏了
核心: dp[i-1]>0 就连上,否则dp[i]=nums[i]只取自己(必须至少取一个啊) 然后到i+1时若dp[i]<0不要就是喽

public int maxSubArray(int[] nums) {
    int[] dp = new int[nums.length];
    dp[0] = nums[0];
    int max=dp[0];
    for (int i = 1; i < nums.length; i++) {
        /*if(dp[i-1]+nums[i]>nums[i]) dp[i] = dp[i-1]+nums[i];
        else dp[i]=nums[i];*/
        dp[i] = Math.max(dp[i-1]+nums[i],nums[i]); // 前面的和>0 加上 否则不加
        max=Math.max(max,dp[i]);
    }
    return max;
}

很明显可以滚动来压缩空间,因为每次dp[i]都只是需要用到dp[i-1]

public int maxSubArray(int[] nums) {
    int dp = nums[0],max=nums[0];
    for (int i = 1; i < nums.length; i++) {
        dp = Math.max(dp+nums[i],nums[i]); // 前面的和>0 加上 否则不加
        max=Math.max(max,dp);
    }
    return max;
}

55. 跳跃游戏

55. 跳跃游戏

public boolean canJump(int[] nums) {
    if(nums.length<=1) return true;
    // 能跨过0元素即可到达
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] == 0) {
            int j = i;
            while (j-- > 0) {
                if (nums[j] > i - j) break;
                else if(nums[j]==i-j&&i==nums.length-1) break;//刚好到最后一个也行
            }
            if (j < 0) return false;
        }
    }
    return true;
}
  • 代码优化

其实最后一个元素不必判断,能跨过前n-1所有的0,肯定能跨过倒数第2个,也就一定能到最后一个

然后再语法层面做一些优化

public boolean canJump(int[] nums) {
    // 能跨过0元素即可到达 (调试发现最后一个不必判断 能跨过前n-1所有的0 一定能到达最后)
    for (int i = 0; i < nums.length-1; i++) {
        if (nums[i] == 0) {
            int j = i;
            while (--j>=0 && nums[j]<=i-j);
            if (j < 0) return false;
        }
    }
    return true;
}

看题解发现一种特别简洁的做法,直接跳就行了,但是时间上慢了

直接跳就行了
能跳到nums[i]其左边的一定能到
每个元素都往最远的跳 都能跳就行

public boolean canJump(int[] nums) {
    // 其实一直跳就行了
    int k = 0;
    for (int i = 0; i < nums.length; i++) {
        if(i>k) return false;
        k = Math.max(k,nums[i]+i);//每个元素都往最远的跳 都能跳就行 能跳到nums[i]其左边的一定能到
    }
    return true;
}

56. 合并区间

56. 合并区间

先直接贪心取一下
过了,就行了吧

public int[][] merge(int[][] intervals) {
   // lambda表达式 指定按照第一维排序一级排序 第二维二级排序
   ArrayList<int[]> list = new ArrayList<>();
   Arrays.sort(intervals,(a1,a2)->a1[0]-a2[0]);
   for (int i = 0; i < intervals.length; i++) {
       int l = intervals[i][0],r=intervals[i][1];
       while (i+1<intervals.length&&r>=intervals[i+1][0]){//注意是维护的当前最大右边界>=intervals[i+1][0]
           r = Math.max(r,intervals[i+1][1]);//需要维护 不一定最后一个第二维就最大
           i++;
       }
       list.add(new int[]{l,r});
   }
   int[][] ans = new int[list.size()][2];
   for (int i = 0; i < list.size(); i++) {
       ans[i] = list.get(i);
   }

   return ans;
}

62. 不同路径

62. 不同路径

  • 方法1,直接用杨辉三角
    在这里插入图片描述
public int uniquePaths(int m, int n) {
    int[][] path = new int[m + 1][n + 1];//外围填充一层0就不用判断边界了
    for (int i = 1; i <=m ; i++) {
        for (int j = 1; j <= n; j++) {
            if(i==1&&j==1) path[i][j] = 1; //这个启始条件还是要有的
            else path[i][j] = path[i-1][j]+path[i][j-1];
        }
    }
    return path[m][n];
}

记得高中学排列组合时有个公式直接能算出来啊,去题解看看吧:

果然是有:
在这里插入图片描述
高中肯定会,读个大学,啥都忘了,唉~

总共移动(m-1)+(n-1)=m+n-2次 , 其中向下m-1次,向右n-1次,也就是m+n-2次中挑出m-1次向下,即: C m + n − 2 m − 1 C_{m+n-2}^{m-1} Cm+n2m1

或者m+n-2次中挑出n-1次向右,即: C m + n − 2 n − 1 C_{m+n-2}^{n-1} Cm+n2n1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/12380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

元宇宙:虚拟仿真技术的全面提升

在当今数字化的世界中&#xff0c;我们经常听到虚拟现实、增强现实、混合现实等技术的名词&#xff0c;这些技术的应用越来越成熟。其中&#xff0c;虚拟仿真技术是一种通过计算机技术来模拟实际场景和对象的过程&#xff0c;它为我们提供了更多的可能性。而最近备受瞩目的元宇…

加密的本质:数学的不对称性

文章目录 引言I 预备知识1.1 加密和授权1.2 非对称的特性II 椭圆曲线加密的方法2.1 椭圆曲线2.2 椭圆曲线的性质引言 不对称有时却自有其妙处与美感,比如黄金分割就是不对称的。 可以通过加密和授权,兼顾保护信息不外泄,而且某些得到授权的人还能使用信息。 I 预备知识 …

亚马逊云科技为全球的可持续发展进程做出贡献

可持续发展是一个涉及经济、环境和社会三个方面的复杂问题。经济发展必须在保护环境和社会公正的前提下进行&#xff0c;这样才能实现真正的可持续发展。为了实现这一目标&#xff0c;人们需要借助技术手段&#xff0c;更好地理解和解决环境和社会问题。 亚马逊云科技是全球领…

(大数据开发随笔9)Hadoop 3.3.x分布式环境部署——全分布式模式

索引 完全分布式模式守护进程布局集群搭建准备总纲配置文件格式化集群启动集群 集群控制命令集群启停进程查看启动日志查看集群常见问题 案例演示&#xff1a;WordCount 完全分布式模式 分布式文件系统中&#xff0c;HDFS相关的守护进程也分布在不同的机器上&#xff0c;如&am…

tp5实现导入excel表到数据库

hello&#xff0c;大家好&#xff0c;好长时间没有更新文章了。最近一直在忙着做项目。所以断更了。 那么好&#xff0c;各位老铁是否想要实现导入导出的功能 请关注我&#xff0c;解密如何实现导入导出&#xff0c; 那么今天先来讲一下用thinkphp5.0 如何实现Excel表格导入数据…

js 事件流程

描述 JavaScript 的执行是单线程的&#xff0c;后面的任务需要等待前面的任务完全完成后&#xff0c;再去执行。DOM 事件&#xff08;文件的加载等&#xff09;、定时器、网络请求等事件&#xff0c;并不会消耗 CPU&#xff0c;这些事件无需等候&#xff0c;所以出现了异步。主…

【Unity VR开发】结合VRTK4.0:创建一个按钮(Option Button)

语录&#xff1a; 如同天上降魔主&#xff0c;真是人间太岁神。 前言&#xff1a; 选项按钮是一种提供多项选择选项的方法&#xff0c;其中只有一个按钮可以处于激活状态&#xff0c;激活另一个按钮时将确保组中的所有其他按钮都已停用。我们可以使用嵌套在预制件中的预制件来实…

C++命名空间域namespace与域作用限制符: :,cin,cout输入输出简单介绍

TIPS C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等C总计63个关键字&#xff0c;C语言32个关键字&#xff0c;具体没有必要先不去管它 域&#xff0c;命名空间域与namespace关键字 cpp需要解决的第一…

数据库中的视图及三级模式结构

文章目录 一、视图二、数据库三级模式结构 一、视图 简单地说&#xff0c;视图可以看成是一个窗口&#xff0c;它所反映的是一个表或若干表的局部数据&#xff0c;可以简化查询语句。视图一经定义&#xff0c;用户就可以把它当作表一样来查询数据。 但视图和基本表不同&#…

400以内的蓝牙耳机哪款好?400以内蓝牙耳机排行榜

谈起TWS&#xff0c;无论是传统的音频厂商还是手机厂商&#xff0c;都是其不可或缺的重要产品线&#xff0c;现在很多许多蓝牙耳机都不是千篇一律得形状&#xff0c;市场也鲜有商家在外观上下功夫&#xff0c;下面分享几款400元以内&#xff0c;内外兼具的耳机品牌。 一、南卡…

Pytorch实现图像风格迁移(一)

图像风格迁移是图像纹理迁移研究的进一步拓展&#xff0c;可以理解为针对一张风格图像和一张内容图像&#xff0c;通过将风格图像的风格添加到内容图像上&#xff0c;从而对内容图像进行进一步创作&#xff0c;获得具有不同风格的目标图像。基于深度学习网络的图像风格迁移主要…

LeetCode热题HOT100:76. 最小覆盖子串,84.柱状图中最大的矩形、96. 不同的二叉搜索树

LeetCode 热题 HOT 100 76. 最小覆盖子串 题目&#xff1a;给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 “” 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字…

ADManager Plus:简化 Active Directory 管理的完美工具

在企业中&#xff0c;Active Directory&#xff08;AD&#xff09;是一个非常重要的组件&#xff0c;用于管理和控制所有计算机和用户的访问权限。然而&#xff0c;AD的管理和维护需要一定的技术能力和时间成本。为了简化这个过程&#xff0c;ManageEngine 推出了 ADManager Pl…

Leetcode-二叉树

1.中序-后序构建二叉树 106. 从中序与后序遍历序列构造二叉树 - 力扣&#xff08;LeetCode&#xff09; 1. 首先根据后序&#xff08;左右中&#xff09;确定顶点元素&#xff1b; 2. 根据顶点元素划分中序序列&#xff1b; 3. 根据划分中序序列中-左子树的长度&#xff0c;进…

数据类型及变量的定义、使用和注意事项

数据类型 计算机存储单元 变量的定义格式&#xff1a; 数据类型 变量名数据值; 我们知道计算机是可以用来存储数据的&#xff0c;但是无论是内存还是硬盘&#xff0c;计算机存储设备的最小信息单元叫“位( bit ) "&#xff0c;我们又称之为“比特位”&#xff0c;通常用…

除了Java,还可以培训学习哪些IT技术?

除了Java&#xff0c;还可以培训学习哪些IT技术&#xff1f; 转行IT学Java似乎已经成为很多人的首选&#xff0c;原因无非是开发技术含量高、开发有前景、开发是一个互联网企业的核心岗位&#xff0c;最重要的是开发薪资待遇高。但其实只单纯因为薪资选择Java的话&#xff0c;小…

百万赞同:网络安全为什么缺人? 缺什么样的人?

1.网络安全为什么缺人? 缺人的原因是有了新的需求 以前的时候&#xff0c;所有企业是以产品为核心的&#xff0c;管你有啥漏洞&#xff0c;管你用户信息泄露不泄露&#xff0c;我只要做出来的产品火爆就行。 这一切随着《网络安全法》、《数据安全法》、《网络安全审查办法》…

什么是机器学习?

目录 简介 机器学习可以做什么 机器学习未来的趋势 总结 简介 机器学习是一种人工智能领域中的技术&#xff0c;其主要目的是让计算机能够自动进行模式识别、数据分析和预测。 机器学习的起源可以追溯到20世纪50年代&#xff0c;当时美国的Arthur Samuel在一篇论文中提出了相关…

静态时序分析Static Timing Analysis4——多时钟域和多时钟时序检查

文章目录 前言一、多时钟域时序分析1、慢时钟域到快时钟域1.1 建立时间检查1.2 保持时间检查1.3 多周期检查 2、快时钟域到慢时钟域2.1 建立时间检查2.2 保持时间检查2.3 合理的约束 3、总结 二、多时钟1、整数倍关系2、非整数倍关系 三、相位移动 前言 2023.4.12 这里讲的多时…

助力研发效能变革,第七届Techo TVP 开发者峰会圆满落下帷幕

引言 在互联网数字企业结束“野蛮扩张”、追求高质量增长的今天&#xff0c;研发效能已然成为企业关注的核心命题。伴随着云原生概念在软件领域的落地生根&#xff0c;云原生正驱动软件应用设计、实现、部署及运维方式的巨变&#xff0c;为研发效能治理带来了新的挑战与机遇&am…
最新文章