leetcode 刷题

1.给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。说明:算法应该具有线性复杂度,不可以使用额外的空间来实现。

解:初看这道题,想到的是把数组中的每一个元素和其他所有元素进行比较,但是这样时间复杂度不满足线性,之后读题理解到,重复的数字均出现2次,这样就可以用异或来解这道题,因为一个数字和它本身异或为0,和0异或是它本身。

 

class Solution {
    public int singleNumber(int[] nums) {
        int num = nums[0];
        for(int i = 1 ;i < nums.length; i++){
            num = nums[i] ^ num;
        }
        return num;
    }
}

2.给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

解:刚开始想的是把数组中的数字合成一个整数,然后加一,在把整数拆分放到数组里面,然而这个方法只能解决一部分题目,遇到特别长的数组,int和long这样的数据类型都无法存储。苦思无解,看了别人的解法,十分巧妙,记下来。

class Solution {
    public int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; i--) {
            digits[i]++;
            digits[i] = digits[i] % 10;
            if (digits[i] != 0) return digits;//没有遇到9,99,999这样的情况,就会从这里退出
        }
        digits = new int[digits.length + 1];//遇到9,99这样的情况,手动给它进位
        digits[0] = 1;
        return digits;
    }
}

3.给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

解:因为缺少一个数字,可以创建一个新的数组比原数组空间多一个,然后把原数组中的值当作新数组的角标,将新数组赋值为1,这样新数组中会有一个元素为0,其角标就为缺少的值。(线性复杂度,线性空间)

class Solution {
    public int missingNumber(int[] nums) {
        int[] newArr = new int[nums.length+1];
        for(int i = 0 ; i < nums.length ; i++){
            newArr[nums[i]] = 1;
        }
        int j = 0;
        for( j = 0 ; j < newArr.length ; j++){
            if(newArr[j] == 0){
                break;
            }
        }
        return j;
    }
}

但是,还有更好解法,根据题目的特殊性,我们可以用前n项公式和求和,接着逐一减去数组中的值。

class Solution {
    public int missingNumber(int[] nums) {
        int sum = (1 + nums.length ) * nums.length / 2;
        for(int i = 0 ; i < nums.length;i++ ){
            sum -= nums[i];
        }
        return sum;
    }
}

4.给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

解:我选择的是先进行排序,然后用遍历一遍,利用计数器来找到众数。

class Solution {
    public int majorityElement(int[] nums) {
        for(int i = 0 ;i < nums.length - 1 ; i++) {
			for (int j = 0; j < nums.length - 1 - i; j++) {
				if(nums[j] > nums[j+1]) {
					int temp = nums[j];
					nums[j] = nums[j+1];
					nums[j+1] = temp;
				}
			}
		}//冒泡排序
        int count = 1;
        int num =nums[0];
        for(int i = 1 ; i < nums.length ; i++){
            if(nums[i] == num){
                count++;
                if(count > nums.length /2)
                    break;
            }else{
                num = nums[i];
                count = 1;
            }
        }
        return num;
    }
}

但是测试用例44个只通过了42个,他给了一个很大的数组,导致解题时间超出限制。

第二种思想:既然众数是出现次数1/2频度以上,那么若现将数组排序,中位数必为众数!(十分巧妙!)

class Solution {
    public int majorityElement(int[] nums) {
        int length = nums.length;
        Arrays.sort(nums);     
        return nums[length/2];
    }
}

第三种思想:摩尔投票法:其他数字出现次数的总和都是比不上这个数字出现的次数 。

设置两个变量  candidate 和 count,candidate 用来保存数组中遍历到的某个数字,count 表示当前数字的出现次数,一开始 candidate 保存为数组中的第一个数字,count 为 1
遍历整个数组
如果数字与之前 candidate 保存的数字相同,则 count 加 1
如果数字与之前 candidate 保存的数字不同,则 count 减 1
如果出现次数 count 变为 0 ,candidate 进行变化,保存为当前遍历的那个数字,并且同时把 count 重置为 1
遍历完数组中的所有数字即可得到结果

class Solution {
    public int majorityElement(int[] nums) {
        int num = nums[0];
        int count = 1;
        for(int i = 0 ; i < nums.length ; i++ ){
            if(nums[i] == num)
                count++;
            else{
                count--;
                if(count==0){
                    num = nums[i];
                    count = 1;
                }
            }
        }
        return num;
    }
}

5.在一个给定的数组nums中,总是存在一个最大元素 。查找数组中的最大元素是否至少是数组中每个其他数字的两倍。如果是,则返回最大元素的索引,否则返回-1。

解:一次遍历,找到最大数字和第二大数字,进行比较即可。

class Solution {
    public int dominantIndex(int[] nums) {
        if(nums.length == 1)
            return 0;
        int max = -1;
        int secondMax = -1;
        int index = -1;
        for(int i = 0 ;i < nums.length ;i++){
            if(nums[i] > max){
                secondMax = max;
                max = nums[i];
                index = i;
            }else{
                if(nums[i] >secondMax)
                    secondMax = nums[i];
            }
                
        }
        if(max / 2 >= secondMax)
            return index;
        else
            return -1;
        
    }
}

6.给定两个有序整数数组 nums1 nums2,将 nums2 合并到 nums1 使得 num1 成为一个有序数组。

说明:初始化 nums1 和 nums2 的元素数量分别为 m 和 n。你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

解: 这道题可以用双指针来解决,类比两堆扑克牌,我把他们倒扣在桌面上,每次打开两牌堆顶上各一张,谁小,就把它放在第三堆,依次进行。这道题由于nums1有足够的空间,双指针可以从后面开始。

class Solution {
  public void merge(int[] nums1, int m, int[] nums2, int n) {
      int p1 = m - 1;
      int p2 = n - 1;
      int p = m + n -1;
      
      while((p1>=0) && (p2 >=0)){
          nums1[p--] = (nums1[p1] < nums2[p2]) ? nums2[p2--] : nums1[p1--];

      }
      System.arraycopy(nums2, 0, nums1, 0, p2 + 1); //如果第一个数组提前结束,就把第二个数组剩下的元素放入第一个

  }
}

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

解:最简单的办法就是暴力解法,用两个for循环来解决问题。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        for(int i = 0 ; i < nums.length ;i++){
            for(int j = i + 1 ; j < nums.length ; j++){
                if(nums[j] == target - nums[i])
                    return new int[] { i, j };

            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

还有一种方法是利用哈希表来解决问题。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();//创建一个哈希表
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];//要查询的元素
            if (map.containsKey(complement)) { //如果要查询的元素在哈希表里就返回位置
                return new int[] { map.get(complement), i };
            }
            map.put(nums[i], i);//没有找到,就将它和它的角标加入哈希表
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

8.(三数之和)

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

解:1.首先对数组进行排序,排序后固定一个数nums[i]nums[i]nums[i],再使用左右指针指向nums[i]nums[i]nums[i]后面的两端,数字分别为nums[L]nums[L]nums[L]和nums[R]nums[R]nums[R],计算三个数的和sumsumsum判断是否满足为 000,满足则添加进结果集
2.如果nums[i]nums[i]nums[i]大于 000,则三数之和必然无法等于 000,结束循环
3.如果nums[i]nums[i]nums[i] == nums[i−1]nums[i-1]nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
4.当sumsumsum == 000 时,nums[L]nums[L]nums[L] == nums[L+1]nums[L+1]nums[L+1]则会导致结果重复,应该跳过,L++L++L++
5.当sumsumsum == 000 时,nums[R]nums[R]nums[R] == nums[R−1]nums[R-1]nums[R−1]则会导致结果重复,应该跳过,R−−R--R−−
时间复杂度:O(n2)O(n^2)O(n2),nnn为数组长度

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList();
        Arrays.sort(nums); //排序
        int len = nums.length;
        if(nums == null || len < 3) return ans;
        for(int i = 0 ; i < len ; i++){
            if(nums[i] > 0 ) break;
            if(i > 0 && nums[i] == nums[i-1]) continue;
            int L = i+1;
            int R = len -1;
            while(L < R){
                int sum = nums[i] + nums[L] +nums[R];
                if(sum == 0){
                    ans.add(Arrays.asList(nums[i] , nums[L] , nums[R]));
                    while (L<R && nums[L] == nums[L+1]) L++; // 去重
                    while (L<R && nums[R] == nums[R-1]) R--; // 去重
                    L++;
                    R--;
                }else if(sum < 0){
                    L++;
                }else{
                    R--;
                }
            }
        }
        return ans;
    }
}


 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值