leetcode(1) 3.16-3.22

3.16–3.22刷题总结

- LeetCode篇

  • 两数之和
    据说是leetcode入门必刷题,小菜鸡在遇到这种题第一反应:暴力!!! 嗯 ,那肯定是不行的,所以,在众多资料中,成功使用HashMap完成了这个题呢。
    暴力法得时间复杂度为O(n2),在要求降低时间复杂度的情况下,则必须用空间来换。
    HashMap
    建立数字与其坐标位置之间的映射,遍历一个数,另一个预先存储。
    思路
    target - 遍历到的数字 = 另一个需要的数字(直接查找是否存在该数)
    步骤
    1) 建立对象,新建数组用来存放索引;
    2) 遍历数组,建立HashMap映射;
    3)二次查找并记录索引。
class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> m = new HashMap<Integer,Integer>();
        int[] res =new int[2];
        for(int i=0 ; i < nums.length ; ++i){
            m.put(nums[i],i);
        }
        for(int i=0 ; i < nums.length ; ++i){
            int t = target -nums[i];
            if(m.containsKey(t) && m.get(t) != i){//m.containsKey(k) 判断是否包含指定的键值
                res[0]=i;
                res[1]=m.get(t);
                break;
            }
        }
        return res;
    }
}

要求
不使用额外的数组空间,必须在原地修改输入数组并使用O(1)额外空间的条件下完成。

思路
因为数组是有序的,所以只需要用后面的元素覆盖前面重复的数即可。使用快慢指针来记录遍历的坐标。
1)开始时两个指针都指向第一个数;
2)若两个数相同,则快指针向前一步;
3)若两个数不同,则快慢指针都向前一步。
则当快指针走完整个数组后,慢指针当前坐标+1既是数组中不同数字的个数。

class Solution {
    public int removeDuplicates(int[] nums) {
        int j = 0;//慢指针 
        int i = 1 ;//快指针
        for(; i < nums.length ; i++){
            if(nums[i] != nums[j]){
                j++;
                nums[j]=nums[i];
            }
        }
        return j+1 ;
    }
}

要求
使用空间复杂度为O(1)的原地算法解决问题。

思路
这个旋转数组的解法有很多中,自己做不出来的情况参考了一下大佬的思路
个人比较喜欢类似字符翻转的方式,嘻嘻嘻嘻嘻哈哈哈哈哈哈 (k->翻转次数)
1) 先把前 n-k 个数字翻转一下;
2)再把后 k 个数字翻转 ;
3)再把整个数组翻转。
在Java中可以使用ArrayList数组,调用Collections.reverse方法实现翻转(小声哔哔 使用Collections.reverse的前提是 数组是ArrayList类型滴)。
(以下,是提交代码)

class Solution {
    public void rotate(int[] nums, int k) {
         int n=nums.length; 
        if(nums.length==0 || (k=k%nums.length)==0)  return;
        reverse(nums,0,n-k-1);
        reverse(nums,n-k,nums.length-1);
        reverse(nums,0,nums.length-1);
    }
    public void reverse(int[] nums, int start,int end){ //翻转函数
        while(start<end){
            int t=nums[start];
            nums[start++] = nums[end] ;
            nums[end--] = t ;
        }
    }
}
  • 只出现一次的数字
    这是一道很神奇的题! 用异或运算符简单解决问题!
    异或运算符
    其是一种基于二进制的位运算,运算符两侧数的每个二进制位同值取0,异值取1.
    还可解决的问题:
    1)一个数组存放若干整数,一个数出现奇数此,其余数均出现偶数次,找出这个穿线奇数次的数。
    2)1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均只出现一次,每个数组元素只能访问一次,不用辅助存储空间,找出该值。
class Solution {
    public int singleNumber(int[] nums) {
     int res=0;
     for(int i=0;i<nums.length;i++){
         res^=nums[i];
     }
     return res;   
    }
}
  • 66-加一
    本题较为简单,但存在一个特殊情况,若数组为 [9] ,则返回 [1,0] 。 这种情况要单独写。
class Solution {
    public int[] plusOne(int[] digits) {
        int  a = digits.length   ;
        for(int i=a-1;i>=0;i--){
            if(digits[i]==9){//末尾数为9 向前进一
                digits[i]= 0;
            }else{
                digits[i]++;//非9 情况
                return digits ;
            }
        }
        digits =new int[a+1]; //特殊情况
        digits[0] =1;
        return digits;
    }
}
  • 移动零
    思路
    双指针解决问题。一个不停的后移,寻找非0位,当找到后与前面的指针交换位置即可。
class Solution {
    public void moveZeroes(int[] nums) {
        for (int i = 0, j = 0 ; i <nums.length ; i++) {
            if(nums[i]!=0){//j每当有一个非0值前移,j++
                int t=nums[j];
                nums[j++]=nums[i];
                nums[i]=t;
            }
        } 
    }
}
  • 两个数组的交集
    思路
    1)定义一个HashSet型数组set用来存放nums1的数据,因为HashSet的特性,nums1中重复的元素已被过滤。
    2)定义一个ArrayList型数组arr用来存放最后输出的数据。
    3)数组set可通过循环键入nums1的数据,在键入arr时循环nums2数组,此时可使用x.contains()方法来判断nums2数组中的元素在set中是否存在,如果存在,arr增加且set删除该数据(因为要求输出的每个元素是唯一的,如果不从set中删除,nums2中与nums1相同的元素会多次输出)。
    4)将ArrayList型数组转化为int型数组输出。
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        HashSet<Integer> set = new HashSet<>();
        ArrayList<Integer> arr = new ArrayList<>();
        for(int num : nums1)       set.add(num);
        
        for(int num : nums2){
            if(set.contains(num)) {
                arr.add(num);
                set.remove(num);
            }
        }
        
        int[] res = new int[arr.size()];
        for(int i = 0; i < arr.size(); i++)
            res[i] = arr.get(i);
      
        return res;
    }
}
  • 字符串中的第一个唯一字符
    思路
    1)假定该字符串中只包含小写字母,建立一个int型数组存放26个字母出现的次数;
    2) 使用循环记录每个字母出现的次数;
    3) 再次循环,将字符串中的字母与记录数组中的数据对比,输出第一个唯一字符
    其中:
    x.toCharArray() 方法是将字符串转换为字符数组,输出结果是字符数组。
class Solution {
    public int firstUniqChar(String s) { 
        int[] len=new int[26];//存储各字符出现次数
        for (char c:s.toCharArray())//第一次遍历
            len[c-'a']++;
            
        for (int i = 0; i <s.length() ; i++) {//第二次遍历
            if(len[s.charAt(i)-'a']==1) 
            	return i;
        }
        return -1;//无解
    }
}
  • 使数组唯一的最小增量
    题目含义
    将数组中存在的数都使其唯一,若存在重复的数,加上最小增量使其成为唯一。
    思路
    1)数组排序
    2)若A[i-1]==A[i],则A[i]++;
    3)若A[i-1] > A[i] , A[i] = A[i-1] + 1 。
class Solution {
    public int minIncrementForUnique(int[] A) {
        Arrays.sort(A); //对数组排序
        int res = 0 ;
        for(int i=1 ; i<A.length ; i++ ){
            if( A[i-1]==A[i] ){   //当排序后 如果相连的两个数值相等 则后者则增  (不需要管后者大于前者的情况)
                A[i]++;
                res++;
            }
            if( A[i-1] > A[i] ){   //当增加操作使得 相邻元素前者大于后者 则res在两数之差上增加1,小元素在大元素的基础上+1
                res = res + A[i-1] - A[i] + 1 ;
                A[i] = A[i-1] + 1 ;
            }
        }
        return res ;
    }
}

在摸索中前进,希望自己不会后悔!
奥利给!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值