二月二十八号 剑指offer_11 and复习

巩固练习

题目一
存在重复元素

本题暴力思路就是首先排好序,然后前一位与后一位比较,(两个for循环)。

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

第二种方法是使用到哈希表,用到set.add判断输出元素是否存在,如果存在,就是重复,返回true,否则false。(set.add(num),如果num存在,不需要添加,返回false,num不存在,即添加进set,返回True。)

class Solution {
    public boolean containsDuplicate(int[] nums) {
            Set<Integer> set = new HashSet<>();
                for(int i:nums){
                    if(!set.add(i))
                    {
                        return true;
                    } 
            } 
            return false;
    }
}
题目二
最大子数组和

没有搞出来呢,难住我了,看懂了一个暴力法,也是超时了,后续再刷。

class Solution {
    public int maxSubArray(int[] nums) {
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < nums.length; i++)
        {
            int sum = 0;
            for (int j = i; j < nums.length; j++)
            {
                sum += nums[j];
                if (sum > max)
                {
                    max = sum;
                }
            }
        }
        return max;
    }
}
题目三
两数之和

两数之和,看到题目,首先想到的还是两个for循环,暴力解决问题。

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

其次再想到的就是哈希函数了,使用了map.containsKey来判断map中是否包含此元素的key,如果包含,就返回当前元素的value和map中的value,其中map.put(nums[i],i);最为重要,位置的错误会导致重复的使用。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
            for(int i=0;i<nums.length;i++){
                if(map.containsKey(target-nums[i])){
                    return new int[]{map.get(target-nums[i]),i};
                }
                map.put(nums[i],i);
            }
        return new int[0];
        }
    }
题目四
合并两个有序数组

暴力法就是直接把nums1后面的空位直接赋值nums2中的元素,最后排序即可。

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

第二种就是双指针,让数组从头开始,排除掉nums1或者num2长度为0情况,按照大小顺序一次插入新数组中。其中出现了个错误,提示 solution merge,翻译为解决方案合并,原因是因为全都写成if语句了,没有使用else if,就一直归并了。(愚蠢哟)

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int x = 0;
        int y = 0;
        int[] a = new int[m + n];
        int t;
        while(x<m||y<n)
        {
            if(x==m){
                t = nums2[y++];
            }
            else if(y==n){
                t = nums1[x++];
            }
            else if(nums1[x]<nums2[y])
            {
                t=nums1[x++];
            }
            else{
                t=nums2[y++];
            }
            a[x+y-1]=t;
        }
        for(int i = 0;i<m+n;i++)
        {
            nums1[i]=a[i];
        }
    }
}

第三种就是双指针逆序,与上一种方法,时间不变,空间减小,不需要新创空间。从后往前,不需要考虑会不会覆盖num1的元素。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int x = m - 1;
        int y = n - 1;
        int len = m + n - 1;
        int cur;
        while(x >= 0 || y >= 0){
            if(x == -1){
                cur = nums2[y--];
            }
            else if(y == -1){
                cur = nums1[x--];
            }
            else if(nums1[x] > nums2[y]){
                cur = nums1[x--];
            }
            else{
                cur = nums2[y--];
            }
            nums1[len--] = cur;
        }
    }
}
题目五
两个数组的交集 II

第一种方法就是先把两个数组排序,然后依次比较,找到相等的值保存。

用到了Arrays.copyOfRange(nums,index1,index2),意思为从nums中提取下标为index1到下标为index2-1的元素,如果nums中没有元素,则返回0;(学到了)

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int length1 = nums1.length, length2 = nums2.length;
        int[] intersection = new int[Math.min(length1, length2)];
        int x = 0,y = 0,t = 0;
        while(x<length1&&y<length2){
            if(nums1[x]>nums2[y]){
                y++;
            }
            else if(nums1[x]<nums2[y]){
                x++;
            }
            else {
                intersection[t] = nums1[x];
                x++;
                y++;
                t++;
            }
        }
        return Arrays.copyOfRange(intersection,0,t);
    }
}

第二种方法用到了哈希表,其中一个定义map.getOrDefaulte(num,0) 意思为提取map中key为num的值,如果没有num,则返回0,如果有,则返回其本身的value。这个确实巧妙,当时看了题解,也一直思考怎么去增加删除。第二种思路就是先把长度小的数组放到哈希表中,并且把每个数出现的个数为value,然后与第二个数组比较,相同的添加到新的数组中,并且哈希中其value减1,value为0的直接删除,即再比较到相同值,不会添加,因为num1中已经用完。然后还是用copyOfRange来输出。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        if(nums1.length>nums2.length){
            return intersect(nums2,nums1);
        }
        Map<Integer,Integer> map = new HashMap<>();
        for(int num:nums1){
            int count = map.getOrDefault(num,0)+1;
            map.put(num,count);
        }
        int[] intersection = new int[nums1.length];
        int index = 0;
        for(int num:nums2){
            int count = map.getOrDefault(num,0);
            if(count>0){
                intersection[index++] = num;
                count--;
                if(count>0){
                    map.put(num,count);
                }
                else{
                    map.remove(num);
                }
            }
        }
        return Arrays.copyOfRange(intersection,0,index);
    }
}
题目六
买卖股票的最佳时机

首选暴力解决,但是这次超时了(糟糕)

public class Solution {
    public int maxProfit(int[] prices) {
        int maxprofit = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxprofit) {
                    maxprofit = profit;
                }
            }
        }
        return maxprofit;
    }
}

于是开始改善,这个对于我来说理解有点晕,每次都是看了就忘,通过循环,找到最低价格买入股票,然后最大利润就是第i天之后的某一天,然后看了很多人的评论,也确实是求最大差的问题。也看到有人用到了动态规划,等学到了再刷本题。

public class Solution {
    public int maxProfit(int prices[]) {
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minprice) {
                minprice = prices[i];
            } else if (prices[i] - minprice > maxprofit) {
                maxprofit = prices[i] - minprice;
            }
        }
        return maxprofit;
    }
}

还有一种相对来说比较容易理解,实时更新min和max的值,并且不会遗漏之类的,感觉这个很优。

class Solution {
    public int maxProfit(int[] prices) {
        int min = prices[0]; // 初始化最小值为第一天的价格
        int max = 0; // 初始最大收益为0
        for (int i = 1; i < prices.length; i++) {
            min = Math.min(prices[i], min);
            max = Math.max(max, prices[i] - min);
        }
        return max;
    }
}

感觉到树和栈有了瓶颈,刷一刷前面的,缓一缓。

还刷了一天offer_11,并不是多难。

剑指 Offer 11. 旋转数组的最小数字

因为number本身升序排序,所以可以直接一遍比较元素大小。也是自己理解出来的,因为后面的那几个元素是小于等于第一个元素的,所以如果小于直接替换,如果不小于,就是和第一个相等,就直接输出target。

class Solution {
    public int minArray(int[] numbers) {
            int target=0;
            for(int i=0;i<numbers.length;i++){
                if(numbers[i]<numbers[target]){
                    target = i;
                    //当然,当找到之后,可以直接break,因为找到就是唯一。
                }
            }
        return numbers[target];
    }
}

当然最简单的就是排序,输出第一个元素了,取巧方法。

class Solution {
    public int minArray(int[] numbers) {
    Arrays.sort(numbers);
    return numbers[0];
    }
}

又学到了二分法,二分法当时确实没有想到,然后去理解,发现确实巧妙,让范围依次缩小,最后找到最小值。

class Solution {
    public int minArray(int[] numbers) {
            int i=0;
            int j=numbers.length-1;
            while(i<j){
                int m = (i + j)/2;
                if(numbers[m]>numbers[j]){i = m+1;}
                else if(numbers[m]<numbers[j]){
                    j = m;
                }
                else {j--;}
            }
    return numbers[i];
}
}

然后又闲来无事,展开了else{j--;},这一展开倒是有了很多错误,然后修改,遇到了好多特殊情况,但是改来改去,还是和原代码差不多,所幸就这样了吧(懒)。

            else if(numbers[j] == numbers[m])
            {
                j--;
            }
            else if(numbers[i] == numbers[m])
            {
                i++;
            }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值