力扣算法_数组篇

日常学习+更新

——截止2023年10月8日

3.无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb",输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb",输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew",输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串。

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成
解决代码:
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 记录字符上一次出现的位置
        int[] last = new int[128];
        for(int i = 0; i < 128; i++) {
            last[i] = -1;
        }
        int n = s.length();
        int res = 0;
        int start = 0; // 窗口开始位置
        for(int i = 0; i < n; i++) {
            int index = s.charAt(i);
            start = Math.max(start, last[index] + 1);
            res   = Math.max(res, i - start + 1);
            last[index] = i;
        }
        return res;
    }
}
//第二种方案
class Solution {
    public int lengthOfLongestSubstring(String s) {
        //维护当前最长不重复字符子串
        Set<Character> set = new HashSet<>();
        int left = 0;
        int right = 0;
        int max = 0;
        while(right<s.length()){
            if(!set.contains(s.charAt(right))){
                //未查到重复字符就一直加,right右移
                set.add(s.charAt(right));
                right++;
            }else{
                //right查到重复字符先不动,left右移,set删left经过的字符,直到重复的这个字符删掉为止
                set.remove(s.charAt(left));
                left++;
            }
            //每一次计算当前set子串的长度
            max = Math.max(max, set.size());
        }
        return max;
    }
}

9.回文数 

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121,输出:true

示例 2:

输入:x = -121,输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:

输入:x = 10,输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

解决方案代码:
class Solution {
    public boolean isPalindrome(int x) {
        if(x < 0)
            return false;//整数为负数肯定不为回文数
        int cur = 0;
        int num = x;
        while(num != 0) {
            cur = cur * 10 + num % 10;
            num /= 10;
            //根据正整数的倒序是否一致,来确定是不是回文数
        }
        return cur == x;
    }
}

 26.删除有序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

示例 1:

输入:nums = [1,1,2],输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4],输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素

解决方案代码:
class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        int slow = 1;
        for(int fast = 1; fast < n; fast++){
            if(nums[fast] != nums[fast - 1] ){
            //双指针 用前面一个不同的覆盖后面的
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

 27.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

输入:nums = [3,2,2,3], val = 3,输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2,输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素

解决方案代码:
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        for(int right = 0; right < nums.length; right++){
            if(nums[right] != val){
                nums[left] = nums[right];
        //反向解决 输出新数组的长度 只需要将与val不同的值输出就行
                left++;
            }
        }
        return left;
    }
}

 35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5,输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2,输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7,输出: 4

解决方案代码:
class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i = 0; i < nums.length; i++){
            if(nums[i] >= target){//数组内按照大小顺序排序 
                return i;//返回索引
            }
        }
        return nums.length;
    //target大于数组里的所有数则返回索引及数组长度
    }
}

 66.加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入:digits = [1,2,3],输出:[1,2,4]
解释:输入数组表示数字 123。

示例 2:

输入:digits = [4,3,2,1],输出:[4,3,2,2]
解释:输入数组表示数字 4321。

示例 3:

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

解决方案代码:
class Solution {
    public int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; i--) {
            if (digits[i] != 9) {//
                digits[i]++;//最后一位不为的先进行加一输出
                return digits;
            } 
            digits[i] = 0;//有一位为9 当前为需要为0 保证前一位为1
        }
                //跳出for循环,说明数字全部是9 整型溢出 重新定义数组
        int[] one = new int[digits.length + 1];
        one[0] = 1;
        return one;
    }
}

 88.合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3,输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0,输出:[1]
解释:需要合并 [1] 和 [] 。合并结果是 [1] 。

示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1,输出:[1]
解释:需要合并的数组是 [] 和 [1] 。合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中

解决方案代码:
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
//m为数组中的元素个数 不是数组长度 数组没有长度限制
        for(int i = 0; i <= n-1; i++){
           nums1[m + i] = nums2[i];//将数组2中的值加到数组1中
        }
        Arrays.sort(nums1);//排序进行输出
    }
}

 136.只出现一次的数字

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

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

示例 2 :输入:nums = [4,1,2,1,2],输出:4

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

解决方案代码:
class Solution {
    public int singleNumber(int[] nums) {
        int ans = nums[0];
        if(nums.length == 1)
            return nums[0];
        
        for(int i = 1;i < nums.length; i++){
            //利用异或循环计算  如果不同则为1
            ans = ans ^ nums[i];
        }
        return ans;
    }
}

 169.多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

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

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

解决方案代码:
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        //诸王争霸赛开始【规则是目前投票数为0的话换候选人,自己人给自己人投票,敌方减票】
        //摩尔投票法为啥成立?因为这里的众数是指大于总数数目的二分之一,举两个个极端例子
        //121311【肯定有相邻的,其他的】或者111123【全部联合起来,敌方都抵消不了】
        int num = nums[0];//我先来做霸王
        int ans = 1;//目前帮派就我一个人,遍历下去看看还有没有自己人为自己撑腰打气,首先遇到对手就被搞下去了
        for(int i = 1; i < nums.size(); ++i){
            if(nums[i] == num){
                ans++;//帮派的人来撑腰了,票数++
            }
            else{
                ans--;//敌方来骚扰我当霸王,票数--
                if(ans== 0){//没了,目前帮派人不够地方多,话语权没有
                    num = nums[i];//更换霸王
                    cnt = 1;//新的霸王重新计数
                }
            }
        }
        //选出来笑到最后的霸王
        return num;
    }
}

414.第三大的数

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 1:

输入:[3, 2, 1],输出:1,解释:第三大的数是 1 。

示例 2:

输入:[1, 2],输出:2,解释:第三大的数不存在, 所以返回最大的数 2 。

示例 3:

输入:[2, 2, 3, 1],输出:1
解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1
解决方案代码:
class Solution {
    public int thirdMax(int[] nums) {
        long a = Long.MIN_VALUE, b = Long.MIN_VALUE, c = Long.MIN_VALUE;
        //默认都为最小的值
        for (long num : nums) {//遍历整个数组
            if (num > a) {
                c = b;
                b = a;
                a = num;//循环中a为第一大 b为第二大 c为第三大
            } else if (a > num && num > b) {
                c = b;
                b = num;
            } else if (b > num && num > c) {
                c = num;//在判断的条件中不添加= 则可以排除相同两个数
            }
        }
        return c == Long.MIN_VALUE ? (int) a : (int) c;//从第一大和第三大中返回最小的值
    }
}

485.最大连续1的个数

给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

示例 1:

输入:nums = [1,1,0,1,1,1],输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

示例 2:

输入:nums = [1,0,1,1,0,1],输出:2

提示:

  • 1 <= nums.length <= 105
  • nums[i] 不是 0 就是 1.
解决方案代码:
class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int count = 0, maxCount = 0;//定义全局变量
        for (int i = 0; i < nums.length; ++i) {//遍历整个数组
            if (nums[i] == 1) {
                count++;//如果数组里面的值为1,count计数+1
            } else {
                maxCount = Math.max(maxCount, count);
                //函数max取最大值,存上阶段连续为1的个数
                count = 0;//数组中遇到0则将计数改为0
            }
        }
        maxCount = Math.max(maxCount, count);
        //比较之前的count最大值与遍历结束后count的值,即为最大连续1的个数
        return maxCount;
    }
}

495.提莫攻击

当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。

正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束  再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。

给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。

返回艾希处于中毒状态的  秒数。

示例 1:

输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。

示例 2:

输入:timeSeries = [1,2], duration = 2
输出:3
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。

提示:

  • 1 <= timeSeries.length <= 104
  • 0 <= timeSeries[i], duration <= 107
  • timeSeries 按 非递减 顺序排列
解决方案代码:
class Solution {
    public int findPoisonedDuration(int[] timeSeries, int duration) {
        int result = duration * timeSeries.length;
		//计算总的中毒时间 忽略重叠时间
        for (int i = 1 ; i < timeSeries.length ; i++) {
        result -= Math.max(0, duration - (timeSeries[i] - timeSeries[i - 1]));
		//在数组中比较前后差值与中毒时间 
		//若大于则取0 否则用前面的总时间减去重叠的时间
    }
    return result;
    }
}

628.三个数的最大乘积

给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

 

示例 1:

输入:nums = [1,2,3],输出:6

示例 2:

输入:nums = [1,2,3,4],输出:24

示例 3:

输入:nums = [-1,-2,-3],输出:-6

 

提示:

  • 3 <= nums.length <= 104
  • -1000 <= nums[i] <= 1000
解决方案代码:
class Solution {
    public int maximumProduct(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);//先对数组进行排序
    return Math.max(nums[0]*nums[1]*nums[n - 1] , nums[n - 1]*nums[n - 2]*nums[n - 3]);
//分析数组三个数组成最大乘积的可能,[0]*[1]*[n-1]或者[n-3]*[n-2]*[n-1] 

    }
}

 645.错误的集合

集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

 

示例 1:

输入:nums = [1,2,2,4],输出:[2,3]

示例 2:

输入:nums = [1,1],输出:[1,2]

 

提示:

  • 2 <= nums.length <= 104
  • 1 <= nums[i] <= 104
解决方案代码:
class Solution {
    public int[] findErrorNums(int[] nums) {
        int[] errorNums = new int[2];//定义输出的数组
        int n = nums.length;
        Arrays.sort(nums);//对数组进行排序,确保遍历的准确性
        int prev = 0;
        for (int i = 0; i < n; i++) {//i=0需要从第一个数开始遍历,前一个数值需要进行赋值操作
            int curr = nums[i];//将数组中的数读取出
            if (curr == prev) {
                errorNums[0] = prev;//如果前后两个数值相等,则为重复数值
            } else if (curr - prev > 1) {
                errorNums[1] = prev + 1;//如果前后两个差值大于1,证明丢失数值
            }
            prev = curr;//***保留前一个数值,方便下次遍历判断
        }
        if (nums[n - 1] != n) {
            errorNums[1] = n;//如果最后一个数值不为n,则证明最后一个数缺失
        }
        return errorNums;
    }
}

统计数组中的元素    645、697、448、442、41、274
数组的改变、移动    453、665、283
二维数组及滚动数组    118、119、661、598、419
数组的旋转    189、396
特定顺序遍历二维数组    54、59、498
二维数组变换    566、48、73、289
前缀和数组    303、304、238

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@斯里

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

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

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

打赏作者

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

抵扣说明:

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

余额充值