LeetCode刷题day01

一.第26题·.有序数组删除重复项

1.题目要求

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

2.实现效果展示

  • 输入数字:nums为0 0 1 1 2 2 3 4 4
  • 调用方法后,输出长度为5
  • 新数组的前五位为0 1 2 3 4

3.方法1:双指针法

  • 使用两个指针
    第一个指针index=1,索引从1开始,因为第一个数字不可能重复。
    第二个指针在for循环中,j从第二个元素开始检验。
  • 注意:因为题目说是有序的数组,重复项是贴在一起的。
  • 逻辑:
    index来标记不重复数组的长度, 其中index-1表示当前不重复数组的最后一个数的索引位置。
    如果j不等于nums[index-1],那它不是重复项,将index此时所在位置的值设置为nums[j];index的长度加1,继续检验。
    如果遇到重复项了,index长度不变,j进入下一次循环。

代码实现如下:

 //方法1;双指针
    public  static  int removeDuplicates(int[] nums) {
        if(nums.length==0){
            return 0;
        }
        int index=1;
        for (int j=1;j<nums.length;j++){
            if (nums[j]!=nums[index-1]){
                nums[index]=nums[j];
                index++;
            }
        }
        return index;
    }

4.方法2:哈希表实现

用哈希表实现,因为它有一个强大的功能,就是主键key不会重复。

步骤:

  1. 先创建一个Integer型的哈希表,将数组的元素通过foreach循环插入主键。
  2. if-else判断,使用containsKey方法来判断哈希表中是否已经有这个主键。
  3. 没有使用put方法添加主键,value记录次数为1。 如果有的话,使用get方法获取之前的次数,在之前的次数上+1。
  4. 将哈希表中的key集合以数组的形式输出即可,并记录大小。

涉及到的方法:
containsKey(key):用于判断哈希表中是否有主键key
get(i):获取哈希表中主键为i的对应value值
keyset():获取主键的集合
toArray():将集合转化为数组形式

实现代码:

  //方法2:哈希表,key-value键值对,因为key不会重复,最后返回哈希表的长度就行
    public static int removeDuplicates2(int []num1){
        HashMap<Integer,Integer> map=new HashMap<>();
        for (int i:num1){          
         //判断哈希表中没有这个值    
            if(!map.containsKey(i)){   
                map.put(i,1);
            }
            else map.put(i,map.get(i)+1);   
        }
        int a=map.size();
        //获取key值的集合对象
        Set<Integer> set=map.keySet();        
        //将哈希表中的键集合,转化为数组
        Object[] keyArray = set.toArray();  
        for (int i=0;i<a;i++){
        //强制转化为int型
            num1[i]= (int) keyArray[i];      
        }
        return a;
    }

二.第27题.数组移除目标元素

1.题目要求

  • 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
  • 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
  • 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

2.实现效果

输入:nums = [3,2,2,3], val = 3 (val为移除元素)
输出:2, nums = [2,2]
解释:函数返回新的长度 2, 并且 nums 中的前两个元素均为 2。

注意:不需要考虑数组中超出新长度后面的元素。
例如:函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

3.方法1:暴力求解

暴力算法,熟悉的两层for循环,把时间复杂度拉得满满的,O(n^2)
解析:

  1. 一开始用size来记录数组大小
  2. 第一层for循环,用来遍历数组,一个个检查元素nums[i]
  3. if语句用来判断遍历的元素是否为要删除的元素
  4. 找到了要删除的元素,通过for循环,将此时i位置后面的元素整体向前移一位。并且每找到一个移除元素,size减少1。
  5. 同时i坐标要减1,一位如果找到了,需要向前移项,移完项后,i位置的元素变了,还需要重新检验。
 public static int removeElement1(int []nums, int val) {
        int size = nums.length;
        for (int i = 0; i < size; i++) {
        // 发现需要移除的元素,就将数组集体向前移动一位
            if (nums[i] == val) { 
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
         // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                i--; 
                size--;  // 此时数组的大小-1
            }
        }
        return size;
    }

4.方法2:双指针法

  1. time:用来记录数组的更新长度,初始化为0
  2. for循环遍历数组,来寻找
  3. 如果nums[i]!=移除元素,就将元素放入更新数组的对应位置,也就是time索引的位置。同时将更新数组的长度time+1。

示例代码如下:

  public static int removeElement(int[] nums, int val) {
        int time=0;        // 记录不等于删除值的数
        for (int i=0;i<nums.length;i++){
            if (nums[i]!=val){
                nums[time]=nums[i]; //如果找到
                time++;
            }
        }
       return time;
    }

三.第1题.两数之和

1.题目要求

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

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

2.方法一.暴力求解

解析:

  • 双循环for,时间复杂度O(N^2)
  • 外层循环,遍历从0到nums.length-2,是两个数的第一个数字的遍历
  • 内存循环,从第一个数字后面遍历到数组结束,是第二个数字的遍历
  • if用来判断两个数字之和是否等于目标值,找到就返回

示例代码如下:

    public static int[] twoSum(int[] nums, int target) {
        int a=nums.length;
        for(int i=0;i<=a-2;i++){
         for (int j=i+1;j<a;j++){
             if(nums[i]+nums[j]==target)
                 return new int[]{i,j};
         }
        }
        throw new IllegalArgumentException("没有该匹配值");
    }

3.方法二.哈希表求解

特点:

  • 边存,边检验是否找到。
  • 时间复杂度变低了。

思路:
先将数组中的第一个元素放入哈希表中,从索引1开始遍历,在放入前,先检验map集合中是否有差值target-nums[i](其中nums[i]为待插值)。
如果找到了,就返回下标。没有找到就将nums[i]插入集合中。

示例代码如下:

  public static int[] twoSum2(int[] nums, int target) {
        int a=nums.length;
        Map<Integer,Integer> map=new HashMap<>();
        map.put(nums[0],0);
        for (int i=1;i<a;i++){
            //判断目前哈希表中有没有差键
            if (map.containsKey(target-nums[i])){
                //有的话,则返回当前下标,并返回哈希表中的差键下标
                return new int []{i,map.get(target-nums[i])};
            }
            //没有存进去
            map.put(nums[i],i);
        }

4.方法三.双指针

  • 使用这个方法,需要实现给数组排好序,时间复杂度也和这有关。
  • start指针从0索引开始; end指针在数组最后,length-1开始。
  • 当nums[start]+nums[end]<target时,start++,起始指针前移。
  • 当nums[start]+nums[end]>target时,end–,尾指针移动。
  • 知道中间两数之和等于target时,返回结果。

示例代码如下:

    public static int[] twoSum3(int[] nums, int target) {
        // 先对数组进行排序
        Arrays.sort(nums);

        int start = 0;
        int end = nums.length - 1;

        // 使用双指针法进行查找
        while (start < end) {
            int sum = nums[start] + nums[end];

            if (sum == target) {
                // 找到目标数对
                return new int[]{nums[start], nums[end]};
            } else if (sum < target) {
                // 当前和小于目标值,增加起始指针
                start++;
            } else {
                // 当前和大于目标值,减少尾指针
                end--;
            }
        }
        // 没有找到符合条件的数对
        return new int[]{};
    }

这是我第一次开始认真准备刷算法题,以前也刷过,但是坚持了一星期就放弃了,我想这次我能将这几个月坚持下来。
准备每天发布一下自己的算法刷题心得吧,每天一篇,一篇两道三个算法题,难的话,就一篇,坚持。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱笑的蓝孩子~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值