面试题 10.11. 峰与谷-贪心-Java

1.题目

2.思路

一定是要读懂题意!读懂题意!读懂题意!重要的事情说三遍。理解以下几个问题

什么是峰?

小大小。这个大的数就是峰。比如1,3,2中3就是峰。这里就是谷峰谷。

什么是谷?

大小大。这个小的数就是谷。比如3,1,2中1就是谷。这里就是峰谷峰。

什么的峰谷顺序可以作为答案?

题目中只写了按照峰谷交替输出。并没有说是否必须保证第一个是峰或者第一个是谷。所以我当时的猜测是两个都可以,后面经过代码测试确实如此。

如果是边界怎么处理?比如第一个数和最后一个数。

如果是开头或者末尾的话,其实就只需要判断一边的大小情况。比如第一个数,只需要判断和右边的大小情况。比如第一个数,如果nums[0] > nums[1] ,代表第一个数是峰值。如果nums[0] < nums[1],代表第一个数是谷值。那么相等呢?接着看。

如果相等的数字怎么办?

注意读题,等于的情况,既可以属于峰值,又可以属于谷值。也就是说第一个数的峰谷判断,假如nums[0] == nums[1], 那么这个数有可能是峰,也可以是谷。需要接下来判断第二个数是峰还是谷。

一个整数数组是不是可以有多个答案?(这里绕了好久,不确定对不对,提交完才确认)

比如第一个样例:

输入:[5, 3, 1, 2, 3]

输出:[5, 1, 3, 2, 3]

这里其实输出的是峰谷峰谷峰的顺序,按照我们上面的理解,其实还可以是以谷开头,也就是下面

输出:[3, 5, 1, 3, 2],这个也是被答案所认可的(一开始测试样例不能通过,但是最终提交是可以通过的)

所以答案可能有多个,只要满足题意就可以。

解决方法一排序+头尾拿

  • 直接对数据进行一个排序,比如Arrays.sort(nums)
  • 然后此时其实就形成了12345,这样类似的序列。我假如要让第一个是峰值。那么我取一个最大的值就可以。然后再取一个最小的值,这样以此类推,就可以形成峰谷峰谷峰。。。序列。
  • 开辟一个新数组保存位置,最后再把新数组的值赋给nums
  • 时间复杂度:O(nlogn),主要是排序的时间
  • 空间复杂度:O(n),开辟了新数组
class Solution {
    public void wiggleSort(int[] nums) {
        int n = nums.length;
        if(n <= 2) return; //两个数以下,直接返回。
        int[]ans = new int[n];
        Arrays.sort(nums);
        boolean high = true; //第一个数字是峰
        int left = 0, right = n - 1;
        for(int i = 0 ; i < n ; i++){
            if(high){
                ans[i] = nums[right];
                right--;
            }else{
                ans[i] = nums[left];
                left++;
            }
            high = !high;
        }
        for(int i = 0 ; i < n ; i++){
            nums[i] = ans[i];
        }

    }
}

解决方法二原地修改--面试想要考察的是这个方法

其实仔细思考,根本没必要对整体数组进行排序,我们只需要挨个遍历就可以了。

在方法一中,我们是一开始默认让第一个数是峰值,也就是high = true.但是我们其实可以判断出原来得数组第一个数到底是不是峰值。直接比较第一个数和第二个数的大小关系即可。

假如nums[0] > nums[1] ,代表第一个数是峰值。下一个数字就是谷值。

假如nums[0] <= nums[1], 代表第一个数谷值。下一个数字就是峰值。

当我们遍历到第二个数字的时候,我们已经通过一个变量知道这个数字是峰值还是谷值。

比如low == true,代表此时这个数一定是谷值,那么要保证第三个数比第二个数大于等于。(如果不满足,就交换位置)

比如low == false,代表此时这个数一定是峰值,那么要保证第三个数比第二个数小于等于。((如果不满足,就交换位置))

最后记得变更下一个数low = !low。

所以这是一个贪心的思想,每次我都可以保证局部都是峰谷峰谷,最终达到一个峰谷峰谷峰谷的状态。

  • 时间复杂度:O(n)
  • 空间复杂度:   O(1)
class Solution {
    public void wiggleSort(int[] nums) {
        int n = nums.length;
        if(n <= 2) return ;
        boolean low = true;  //判断一开始是峰还是谷,low = true, 代表第一个位置是谷
        if(nums[0] > nums[1]) low = false; //low = false, 代表是峰

        for(int i = 1 ; i < n - 1 ; i++){
            if(low){ // 这个位置元素必须是谷
                if(nums[i + 1] > nums[i])
                    swap(nums, i + 1, i);
            }
            else{ //这个位置元素必须是峰
                if(nums[i + 1] < nums[i])
                    swap(nums, i + 1, i);
            }
            low = !low;
        }

    }
    public void swap(int[]nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

3.结果

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值