[力扣每日刷题]

本文详细解析了六道编程题目,包括判断数组是否存在重复元素、存在重复元素II、求解一周中的某一天、简化路径、括号的最大嵌套深度以及格雷码序列的生成。主要涉及数组操作、哈希集应用、字符串处理和递归等算法,同时展示了多种解题思路和优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1: 217. 存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

示例 1:
输入: [1,2,3,1]
输出: true

示例 2:

输入: [1,2,3,4]
输出: false

示例 3:

输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

分析:只要所给数组中存在重复元素就返回true,不村子重复元素则返回false
方法一:暴力解法

class Solution {
    public boolean containsDuplicate(int[] nums) {
        for(int i = 0;i<nums.length-1;i++){
            if(nums[i] == nums[i+1]){
                return true;
            }
        }
        return false;
    }
}

方法二:因为HashSet集合中的元素是不可重复的,所以我们可以使用set添加数组元素,如果不能加入,则说明有重复元素,返回true,如果正常遍历完,则返回false;

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet();
        for(int num : nums){
            if(!set.add(num)){
                return true;
            }
        }
        return false;
    }
}

2: 219. 存在重复元素 II

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

示例 1:
输入: nums = [1,2,3,1], k = 3
输出: true

示例 2:
输入: nums = [1,0,1,1], k = 1
输出: true

示例 3:
输入: nums = [1,2,3,1,2,3], k = 2
输出: false

分析:题目要求给出的数组中要存在重复元素,并且他们两除了值相等,还要满足下标差的绝对值小于等于K值;反过来就是说
方法一:暴力解法,循环遍历,但是并不需要全部遍历理由如下:外层循环因为是两个值进行比较,所以只要遍历到倒数第二个即可,内层循环范围满足i+k <=j,且小于数组长度length;
在这里插入图片描述

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
       for(int i = 0;i<nums.length -1;i++){
           for(int j=i+1;j<=i+k&&j<nums.length;j++){
               if(nums[i] == nums[j]){
                   return true;
               }
           }
       }
    }
}

方法二:使用HashSet,因为它的集合中元素是不可重复的;通过循环往set集合中添加元素,当添加的元素个数为k个时,对于集合中的第一个位置元素来说,第k+1个元素是最后一个满足条件的元素,如果它也相等,对于第一个位置的元素来说后面的值就算值与它相等,但是下标的绝对值也不符合条件了,所以需要将它从集合中删除掉。在第k+1个元素之前,只要遍历的值不能在集合中存在,就返回false;正常遍历完,就返回false;

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
       HashSet<Integer> set = new HashSet();
       for(int i = 0;i<nums.length;i++){
           if(set.contains(nums[i])){
               return true;
           }
           set.add(nums[i]);
           if(set.size()>k){
               set.remove(nums[i-k]);
           }
       }
       return false;
    }
}

3:1185. 一周中的第几天

给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。
输入为三个整数:day、month 和 year,分别表示日、月、年。
您返回的结果必须是这几个值中的一个 {“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}。

示例 1:
输入:day = 31, month = 8, year = 2019
输出:"Saturday"

示例 2:
输入:day = 18, month = 7, year = 1999
输出:"Sunday"

示例 3:
输入:day = 15, month = 8, year = 1993
输出:"Sunday"

提示: 给出的日期一定是在 1971 到 2100 年之间的有效日期。

分析:查询可知1971年1月1日为星期四,对于这道题我们可以先求出总天数,再对7 取余即可;只不过整除 就是星期四,余1,是星期五,以此类推;
可以分为三部分求天数,
第一部分:1971年到输入的year年份之间经历的天数;
第二部分:遍历从1-所给的月份之间的天数;
第三部分:所给的天数;
注意:1,3,5,7,8,10,12月为31天,二月如果是闰年是29天,平年28天,其他月是30天

class Solution {
    public String dayOfTheWeek(int day, int month, int year) {
       String[] strs = {"Thursday","Friday","Saturday","Sunday","Monday","Tuesday","Wednesday"};
        int days = 0;
       //统计1971年到输入的year年份之间经历的天数;
       for(int i = 1971;i<year;i++){
           if(isRun(i)){
               days += 366;
           }else{
               days += 365;
           }
       }
        //统计遍历从1-所给的月份之间的天数;
        for(int i = 1;i<month;i++){
            if(i == 4 || i==6 || i== 9 || i==11){
                days += 30;
            }else if(i == 2){
                if(isRun(year)){
                    days += 29;
                }else{
                    days += 28;
                }
            }else{
                days += 31;
            }
        }
        //统计所给的天数;
        days += day;
        return strs[days % 7];
    }
     //定义一个判断是否是闰年的方法;
     public boolean isRun(int year){
         if(year % 400 == 0 ||(year % 4==0&&year % 100 != 0)){
             return true;
         }else{
             return false;
         }
     }
}

在这里插入图片描述

4: 71. 简化路径

给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,’//’)都被视为单个斜杠 ‘/’ 。 对于此问题,任何其他格式的点(例如,’…’)均被视为文件/目录名称。

请注意,返回的 规范路径 必须遵循下述格式:
    始终以斜杠 '/' 开头。
    两个目录名之间必须只有一个斜杠 '/' 。
    最后一个目录名(如果存在)不能 以 '/' 结尾。
    此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。

返回简化后得到的 规范路径 。

示例 1:
输入:path = "/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。 

示例 2:
输入:path = "/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。

示例 3:
输入:path = "/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换

示例 4:
输入:path = "/a/./b/../../c/"
输出:"/c"

提示:
    1 <= path.length <= 3000
    path 由英文字母,数字,'.','/' 或 '_' 组成。
    path 是一个有效的 Unix 风格绝对路径。

分析:根据题目我们可以知道有字符是按/分隔的,所以我们可以将字符串按/进行分隔,刚好有split()方法;以"/a/./b/…/…/c/“位列,分隔后我们会得到字符数组:a,.,b,…,…,c;根据输出可知,a目录下b目录下在退两步,所以到跟目录,再进一级到c,会发现它和栈相似,因为我们的栈是后进先出,刚好符合它的规律;
根据题意可知有这三种情况:1.若是”.“表示本目录,也就是不做任何操作;2.”…"表示要退一级,也就是将该字符串出栈;3.其他字符就是文件或是目录名;将其进栈即可,废话少说,上代码。

class Solution {
    public String simplifyPath(String path) {
        String[] paths = path.split("/");
     //Java官方推荐使用Deque替代Stack使用
        Deque<String> stack = new ArrayDeque<String>();
        //遍历分隔的数组
        for(String name : paths){
            if("..".equals(name)){
            //在栈有元素情况下,将栈顶元素退出
                if(!stack.isEmpty()){
                
                    stack.pollLast();
                }
            }else if(name.length()>0 && !".".equals(name)){//不是"."的文件或目录名进栈
                stack.offerLast(name);
            }
        }
        StringBuffer buffer = new StringBuffer();
        /若栈元素为空,则表示没有子目录,或是文件,添加“/if(stack.isEmpty()){
            buffer.append("/");
        }else{//有元素,全部添加到字符串。
            while(!stack.isEmpty()){
                buffer.append("/");
                buffer.append(stack.pollFirst());
            }
        }
        return new String(buffer);
    }
}

5: 1614. 括号的最大嵌套深度

如果字符串满足以下条件之一,则可以称之为 有效括号字符串(valid parentheses string,可以简写为 VPS):
字符串是一个空字符串 “”,或者是一个不为 “(” 或 “)” 的单字符。
字符串可以写为 AB(A 与 B 字符串连接),其中 A 和 B 都是 有效括号字符串 。
字符串可以写为 (A),其中 A 是一个 有效括号字符串
类似地,可以定义任何有效括号字符串 S 的 嵌套深度 depth(S):
depth("") = 0
depth© = 0,其中 C 是单个字符的字符串,且该字符不是 “(” 或者 “)”
depth(A + B) = max(depth(A), depth(B)),其中 A 和 B 都是 有效括号字符串
depth("(" + A + “)”) = 1 + depth(A),其中 A 是一个 有效括号字符串

例如:""、"()()"、"()(()())" 都是 有效括号字符串(嵌套深度分别为 0、1、2),而 “)(” 、"(()" 都不是 有效括号字符串 。
给你一个 有效括号字符串 s,返回该字符串的 s 嵌套深度 。

示例 1:

输入:s = "(1+(2*3)+((8)/4))+1"
输出:3
解释:数字 8 在嵌套的 3 层括号中。

示例 2:

输入:s = "(1)+((2))+(((3)))"
输出:3

示例 3:

输入:s = "1+(2*3)/(2-1)"
输出:1

示例 4:

输入:s = "1"
输出:0

分析:题目那么长,无非是说统计“(”“)”的嵌套数,最后返回最大的数即可;所以我们很容易想到使用栈的思想;但是使用该思想就够了,没必要想太多,我就是那一种:
先看我看完题就写的代码:

class Solution {
    public int maxDepth(String s) {
        char[] strs = s.toCharArray();
        Deque<Character> stack = new LinkedList<Character>();
        int count = 0;
        int num = 0;
        int temp = 0;
        for(char str : strs){
            if('('== str){
                stack.addFirst(str);
                count++;
                num = count;
            }else if(')'==str){
                num = Math.max(temp,num);
                temp = num;
                if(!stack.isEmpty()){
                    stack.pollLast();
                    count--;
                }
            }
        }
        return num; 
    }
}

官方给的:

class Solution {
    public int maxDepth(String s) {
        int count = 0,result = 0;
        for(int i =0;i<s.length();i++){
            char ch = s.charAt(i);
            if(ch == '('){
                count++;
                result = Math.max(result,count);
            }else if(ch==')'){
                count--;
            }
        }
        return result;
    }
}

总结以下:知道用该思想就行,没必要真用栈,它又不是进行匹配,就光写代码了,没深思以下;思路一模一样;还需努力

6.n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:

每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 1)
第一个整数是 0
一个整数在序列中出现 不超过一次
每对 相邻 整数的二进制表示 恰好一位不同 ,且
第一个 和 最后一个 整数的二进制表示 恰好一位不同

给你一个整数 n ,返回任一有效的 n 位格雷码序列 。

示例 1:

输入:n = 2
输出:[0,1,3,2]
解释:
[0,1,3,2] 的二进制表示是 [00,01,11,10] 。
- 00 和 01 有一位不同
- 01 和 11 有一位不同
- 11 和 10 有一位不同
- 10 和 00 有一位不同
[0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。
- 00 和 10 有一位不同
- 10 和 11 有一位不同
- 11 和 01 有一位不同
- 01 和 00 有一位不同

示例 2:

输入:n = 1
输出:[0,1]

分析:数字格雷码与对应的二进制码有如下表达式关系:(i>>1)^i;如2对应的格雷码为(2>>1) ^ 2 = 3; 3对应的格雷码为 (3>>1) ^ 3 = 2; 兵器n位二进制数可以组合成的十进制数有 2的n次方个。

class Solution {
    public List<Integer> grayCode(int n) {
        List<Integer> list = new ArrayList<Integer>();
        //使用<<运算2的n次方,即十进制数个数;
        for(int i = 0;i< 1<<n;i++){
            list.add((i>>1)^i);
        }
        return list;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心尘未泯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值