LeetCode数组算法题(Java版)

一、删除有序数组中的重复项(26题)

原题如下:

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。



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


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

1.双指针解法

如果数组长度为0则返回0;
定义一个快指针和一个慢指针,因为只要数组长度大于等于1了,他就至少返回一个不一样的数字。
所以我们从1号元素开始检索。我们的慢指针指向下一个元素要填入的位置,快指针从1开始遍历到第nums.length-1个元素,当nums[fast]!=nums[fast-1])的时候,说明num[fast]是一个没出现过的新数字(数组有序)我们就把快指针指向的数字赋值给慢指针,同时慢指针++,最终我们返回慢指针就ok了
num[0]-num[slow-1]就是我们要的答案。

参考代码:

class Solution {
    
    
    public int removeDuplicates(int[] nums) {
    
    
        if(nums.length==0){
    
    
            return 0;
        }
        int slow=1;
        int fast=1;
        for(;fast<nums.length;fast++){
    
    
            if(nums[fast]!=nums[fast-1]){
    
    
                nums[slow]=nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

二、买股票的最佳时机(122题)

原题如下:

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例1
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 
这笔交易所能获得利润 = 5-1 = 4 
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 
这笔交易所能获得利润 = 6-3 = 3 


示例2
输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0


示例3
输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5  (股票价格 = 5)的时候卖出,
这笔交易所能获得利润 = 5-1 = 4 
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,
你必须在再次购买前出售掉之前的股票。


1.动态规划

我研究了半天没研究明白,下次一定。

2.贪心算法

因为此题不规定我们出售和买入的次数,所以只要我们把所有的上升沿全部累加就可以得到最大利润了。但是这种解法的缺陷也很明显,他只能算出我们最终获得的利润,并不能准确的求出我们买入和售出的下标。

参考代码:

class Solution {
    
    

    public int maxProfit(int[] prices) {
    
    
        if(prices==null||prices.length<=1){
    
        
            return 0;
        }
        int ret=0;
        for(int i=0;i<prices.length-1;i++){
    
        //循环遍历每一天
            if(prices[i]<prices[i+1]){
    
             //只要明天的价格大于今天的就卖出 
                ret+=prices[i+1]-prices[i];   
            }
        }
        return ret;
    }
}

三、轮转数组(1868题)

原题如下:

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。


示例1
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 : [7,1,2,3,4,5,6]
向右轮转 2 : [6,7,1,2,3,4,5]
向右轮转 3 : [5,6,7,1,2,3,4]




1.使用额外数组

从新开辟一个数组用来存放移动之后的各个元素。这种方法需要开辟新的空间对内存的损耗较大,但是很容易想到。

其中我们会用到一个拷贝方法:
System中提供了一个native静态方法arraycopy(),可以使用这个方法来实现数组之间的复制。
System.arraycopy(Object srcArray,int srcPos,Object destArray ,int destPos,int length)
Object src : 原数组
int srcPos : 从元数据的起始位置开始
Object dest : 目标数组
int destPos : 目标数组的开始起始位置
int length : 要copy的数组的长度

参考代码:

class Solution {
    
    
    public void rotate(int[] nums, int k) {
    
    
        k=k%nums.length;
        int n=nums.length;
        int[]arr=new int[n];
        for(int i=0;i<n;i++){
    
    
            arr[(i+k)%n]=nums[i];
        }
        System.arraycopy(arr,0,nums,0,n);
       }
}

2.翻转数组

首先我们知道移动数组长度次相当于没有移动,所以我们上来先把k对length取余得到有效移动次数。
我们只需要先将原来数组翻转一次,然后分别将前k个元素和其余元素再次翻转便可得到右移k次的新数组

在这里插入图片描述

参考代码:

class Solution {
    
    
    public void rotate(int[] nums, int k) {
    
    
        k=k%nums.length;
        swap(0,nums.length-1,nums);
        swap(0,k-1,nums);
        swap(k,nums.length-1,nums);
       }
    
    public static void swap(int start,int end,int[] arr){
    
       //翻转方法
        while(start<end){
    
    
            int temp=arr[end];
            arr[end]=arr[start];
            arr[start]=temp;
            end--;
            start++;
        }
    }
}

思考:如果将右旋改为左旋则代码该如何修改?

四、存在重复元素(1898题)

给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 


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


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

1.排序比对

先将数组排序,然后遍历数组比对相邻两个元素是否相等。

参考代码:

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

五、两个数组的交集 II(1505题)

给定两个数组,编写一个函数来计算它们的交集。

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


示例2
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
 

1.双指针大法

先将两个数组进行排序
定义两个指针分别指向两个数组的头,如果指向的值相等则同时后移并记录,不相等则值较小的指针向后移动一位,当有一个数组遍历完则停止。

class Solution {
    
    
    public int[] intersect(int[] nums1, int[] nums2) {
    
    
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int len1=nums1.length;
        int len2=nums2.length;
        int[] arr = new int[Math.min(len1, len2)];
        int a=0;int b=0;int c=0;   //a指向len1,b指向len2,c指向放答案的数组arr
        while(a<len1&&b<len2){
    
    
            if(nums1[a]<nums2[b]){
    
    
                a++;
            }
            else if(nums1[a]>nums2[b]){
    
    
                b++;
            }
            else if(nums1[a]==nums2[b]){
    
    
                arr[c]= nums1[a];
                a++;
                b++;
                c++;
            }
        }
        return Arrays.copyOfRange(arr, 0, c);

我们不能直接输出arr因为arr的大小使我们两个数组中较小的内而过数组的长度,我们相等的元素个数可能没有那么多,这样就会出现输出的arr后面有0的情况,所以我们再输出的时候要使用Arrays.copyOfRange方法把0下标到c下标的元素输出。
如果直接return arr结果会无法通过所有的测试用例 (如下图) 。

在这里插入图片描述
介绍一下Arrays.copyOfRange方法

Arrays.copyOfRange(T[]arr,int start,int end)

复制arr数组从start下标复制到end下标

思考:如果将第三题轮转数组右旋改为左旋则代码该如何修改?

猜你喜欢

转载自blog.csdn.net/weixin_50302770/article/details/121412972