算法入门-刷题

第一部分:数组

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 中的元素。

第一种思路: 直接将两个数组进行合并,然后重新使用Arrays类的方法sort进行排序

class Solution {
    public static void merge(int[] nums1, int m, int[] nums2, int n) {
       for(int i = m + n -1;i > m - 1;i--,n--){
            nums1[i] = nums2[n-1];
       }
       Arrays.sort(nums1);
    }
}

//或者上面的for语句可以使用Java中用于数组拷贝的方法之一:System.arraycopy(nums2,0,nums1,m,n),具体而言,它表明将数组nums2中的元素从索引0开始,拷贝到数组nums1的索引从m开始的位置,拷贝的元素个数为n个。这会覆盖nums1中相应位置的元素。
注意:第二种和第三种方法都可以再定义第三个指针,用于存放要放入的数据

第二种思路: 使用两个指针,同时创建一个大小为Nums1.length的数组temp,然后指针分别指向两个nums数组的第一个元素,比较两个指针指向的元素,较小的元素放入temp数组中,最后根据要求,令nums1指向temp

class Solution {
    public static void merge(int[] nums1, int m, int[] nums2, int n) {
       int[] temp = new int[m+n];
       System.arraycopy(nums1,0,temp,0,m);
       //拷贝nums1到temp中,题目要求输出nums1
       int p = 0;
       int p1 = 0;
       int p2 = 0;
       while(p1<m && p2<n){
        if(temp[p1]<=nums2[p2])
            nums1[p++] = temp[p1++];
        else
            nums1[p++] = nums2[p2++];
       }
        while(p1<m)
            nums1[p++] = temp[p1++];
        while(p2<n){
            nums1[p++] = nums2[p2++];
    }
}

第三种思路(第二种方法的改进): 同样使用两个指针,但是不用再额外创建数组,这时指针指向两个数组实际的最后一个元素(按照上面的实例,nums1指向3,nums2指向6),然后比较大小,较大的元素放入到从后往前的nums1中

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

169. 多数元素

题目:

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

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

第一种思路:

暴力直接统计这个数组中各数字出现的次数,可以使用字典的形式采用HashMap集合,最后根据题目的意思,返回值是一个int,这里我感觉题目不严谨,返回值当然可以不止一个呢(修改也很简单,就略过了),不过按题目意思找到一个就直接break吧,这里可以复习一下:

这里还可以注意下:泛型类型不能使用基本数据类型作为类型参数。因此,HashMap<int, int>是不合法的

在 Java 中,可以使用不同的方式遍历 HashMap。以下是两种常见的遍历方式:

  1. 使用 keySet() 方法遍历键,然后通过键获取对应的值:

     for (String key : map.keySet()) {            
            System.out.println(key + " : " + map.get(key));       
     }
    
  2. 使用 entrySet() 方法遍历键值对:

    for (Map.Entry<String, Integer> entry : map.entrySet()) {
                System.out.println(entry.getKey() + " : " + entry.getValue());
            }
    • map.entrySet() 返回一个包含键值对的 Set 集合,每个元素都是 Map.Entry 对象,代表了 HashMap 中的一个键值对。
    • 在循环中,Map.Entry 指定了这个键值对的类型,其中 String 是键的类型,Integer 是值的类型。
    • 循环内部可以通过 entry.getKey() 来获取当前键值对的键,通过 entry.getValue() 来获取当前键值对的值。

    这种方式遍历 HashMap 的好处是可以同时访问键和值,代码简洁清晰。如果需要遍历 HashMap 中的所有键值对,这种方式是推荐的使用方式。

class Solution {
    public int majorityElement(int[] nums) {
        int l = nums.length/2;
        int re = 0;
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i = 0;i<nums.length;i++){
            if(map.containsKey(nums[i]))
				//map.get(nums[i])++;在Java中,map.get(nums[i])++ 这种写法是无效的,
				//因为 map.get(nums[i]) 返回的是一个值,而不是一个引用。
				//不能直接对这个值进行自增操作。
                map.put(nums[i], map.get(nums[i]) + 1);
             else
                map.put(nums[i],1);
        }
        for(Map.Entry<Integer,Integer> entry : map.entrySet()){
            if(entry.getValue() > l){
                re = entry.getKey();
                break;
            }
        }
        return re;
    }
}

第二种思路(Boyer-Moore 投票算法):

如果我们把众数记为 +1,把其他数记为 −1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。

我们维护一个候选众数 candidate 和它出现的次数 count。初始时 candidate 可以为任意值,count 为 0;

然后遍历这个数组,首先判断count的值,如果count为0,就把nums数组的元素x赋值给candidate,然后再判断x是否等于candidate,这里当count为0时是先赋值再判断是否相等,所以赋完值后count再加1,如果x不等于candidate,则count减去一,当count再次为0时则再次赋值......

再遍历完成后,这个candidate就是多数元素(众数)

或者

可以通过一个事实理解:如果一个数组有大于一半的数相同,那么任意删去两个不同的数字,新数组还是会有相同的性质。

注意是删除两个不同的数字

class Solution {
    public int majorityElement(int[] nums) {
        int candidate = 0;
        int count = 0;
        for(int i = 0; i < nums.length; i++){
            if(count == 0)
                candidate = nums[i];

            if(candidate==nums[i]){
                count++;
            }else{
                count--;
            }}
        return candidate;
    }}
//此处代码的语句优化上,可以将for(int i = 0; i < nums.length; i++)换为:for (int num : nums),直接遍历数组的元素,同时简单的if,else语句可以使用三元运算符进行替换,如此处可以改为:
//count += (candidate==nums[i]) ? 1 : -1

//最后代码可以精简为:
class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        Integer candidate = null;
        for (int num : nums) {
            if (count == 0) {
                candidate = num;
            }
            count += (num == candidate) ? 1 : -1;
        }
        return candidate;
    }}

开始刷算法,也是为了监督自己~~

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值