leetcode刷题打卡(数组2)

剑指 Offer 03. 数组中重复的数字(简单)

找出数组中重复的数字。


在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 

1.哈希表

class Solution {
    public int findRepeatNumber(int[] nums) {
        Map<Integer,Integer> map=new HashMap<>();
        for(int num:nums){
            if(map.containsKey(num))return num;
            else map.put(num,1);
        }
        return -1;
    }
}

2.原地置换(用数组构建哈希表)

class Solution {
    public int findRepeatNumber(int[] nums) {
        boolean[] bool = new boolean[nums.length];
        for(int i=0;i<nums.length;i++){
            if(bool[nums[i]]==true){
                return nums[i];
            }
            bool[nums[i]]=true;
        }
        return -1;
    }
}

剑指 Offer 66. 构建乘积数组(中等)

给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。

示例:

输入: [1,2,3,4,5]
输出: [120,60,40,30,24]

模拟,找规律  

细画一下可以发现,能够分为上下三角,B数组先A数组走一步即可

先计算下三角(左边),

再计算上三角(右边),并累积左边的

class Solution {
    public int[] constructArr(int[] a) {
        //每次res都先行一步
        int[] res=new int[a.length];
        int tmp1=1;
        int tmp2=1;
        for(int i=0;i<a.length;i++){
            res[i]=tmp1;//计算左边
            tmp1=tmp1*a[i];
        }
        for(int i=a.length-1;i>=0;i--){
            res[i]*=tmp2;//计算右边,并累积左边
            tmp2=tmp2*a[i];
        }
        return res;
    }
}

135. 分发糖果(困难)

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
     第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

贪心算法:

先给每个人一颗糖,满足条件1

对于条件2:

左贪心:从左往右,遇到比前一个大的就在前一个基础上加1

右贪心:再从右到左,同理

最后取两边都满足的值(即最大值,为什么是最大值可以自己假设推一下,不难)

class Solution {
    public int candy(int[] ratings) {
        int[] left=new int[ratings.length];  
        int[] right=new int[ratings.length];  
        Arrays.fill(left,1);
        Arrays.fill(right,1);
        for(int i=1;i<ratings.length;i++){
            if(ratings[i]>ratings[i-1])left[i]=left[i-1]+1;
        }
        int count=left[left.length-1];
        for(int i=ratings.length-2;i>=0;i--){
            if(ratings[i]>ratings[i+1])right[i]=right[i+1]+1;
            count+=Math.max(left[i],right[i]);
        }
        return count;
    }
}

空间遍历(空间复杂度低,效率优于贪心):

从左边开始,初始化四个变量:计数器count,当前同学糖果pre,升序长度,降序长度。

为什么要计算升序和降序长度呢?

(无论升序还是降序,当前序列长度都和某一同学最大糖果数相同)

当升序与降序长度相同时会出现特殊情况:降序中的第一个糖果数(降序中最大的)会与升序的最后一个糖果数相等(升序中最大的),这个时候就需要将升序的最后一个并入降序(不能将降序并入升序,不合规则),并入的操作其实很简单,糖果总数加1即可,这个1就是补给升序的最后一个的,方便它能并入降序(使得升序最后一个大于降序的第一个)。

class Solution {
    public int candy(int[] ratings) {
        //计数器
        int count=1;
        //当前同学糖果,升序长度,降序长度
        int pre=1,asc=1,dec=0;
        for(int i=1;i<ratings.length;i++){
            if(ratings[i]>=ratings[i-1]){
                dec=0;//升序
                pre=ratings[i]==ratings[i-1]?1:pre+1;//遇到相等的,多给一个即可
                count+=pre;//计数
                asc=pre;//更新升序长度
            }else{
                dec++;//降序,这个相当与之前已经分配糖果的同学向后平移,而不是越往后越多
                if(dec==asc)dec++;//当降序长度与升序长度相同时,将升序最后一个并入降序
                count+=dec;//计数
                pre=1;//更新当前同学的糖果数
            }
        }
        return count;
        

    }
}

链接:https://leetcode-cn.com/

来源:力扣(LeetCode)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟养成计划111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值