记第一次参加力扣周题【C语言实现第268场力扣周赛】

第268场周赛

上午打完疫苗回来,已经十一点多了,十点半开始的周赛过了一半。不过还是写一写吧,毕竟上周也是推到这周,这周不能再拖延了,总得起个头。一共写出来2道题,因为晚入场了四十分钟左右,排名太拉跨了,才3050名。第一次参加,也不知道自己这个垃圾多少名才是合理的。

image-20211121131420060

可以看出来,我第二题和第一题之间只隔了8分钟,还是很不错的。不过第三题对C语言用户太不友好了,第四题时间复杂度也很不友好,哼,气人。

下面看题吧。

第一题

两栋颜色不同且距离最远的房子

街上有 n 栋房子整齐地排成一列,每栋房子都粉刷上了漂亮的颜色。给你一个下标从 0 开始且长度为 n 的整数数组 colors ,其中 colors[i] 表示第 i 栋房子的颜色。

返回两栋颜色不同房子之间的最大距离。

第 i 栋房子和第 j 栋房子之间的距离是 abs(i - j) ,其中 abs(x) 是 x 的绝对值。

分析

分析一下,这两栋房子一定有一栋在边上。如果不是在边上,比如是 xxxxx5xxxxx4xxxxx ,是不是意味着 4 后面的值都是 5 ,不然就会和 5 匹配了; 5 前面的数字一定是 4 ,不然也会和 4 匹配,那么就是 444445xxxxx455555,就和假设矛盾了。所以一定是至少有一个在边上。

思路一

没有想到一定有个在边上的,用的递归。判断左右两边是否相等,不等的话,就返回结果。相等的话,最终结果一定出在 s + 1 到 t 内或者 s 到 t - 1 内。超时了,因为很多没必要的计算。

int my_max(int *nums, int s, int t)
{
   
    if (s == t) return 0;
    if (nums[s] != nums[t])
        return t - s;
    else 
        return fmax(my_max(nums, s + 1, t), my_max(nums, s, t - 1));
}
int maxDistance(int* colors, int colorsSize){
   
    return my_max(colors, 0, colorsSize - 1);
}
思路二

双指针,指向首尾。假设一定有第一个元素,那么就只用挪动尾指针,直到不等,求得一个最大距离;一定有最后一个元素,那么只用挪动首指针,直到不等,求得一个最大距离。最终结果就是两个中的最大值。

int my_max(int *nums, int left, int right)
{
   
    int s = left, t = right;
    int max1 = 0, max2 = 0;
    while (s < t) {
   
        if (nums[s] != nums[t]) {
   
            max1 = t - s;
            break;
        }
        while(s < t && nums[s] == nums[++s]);
    }
    s = left; t = right;
    while (s < t) {
   
        if (nums[s] != nums[t]) {
   
            max2 = t - s;
            break;
        }
        while(t > 0 && nums[t] == nums[--t]);
    }
    return fmax(max1, max2);
}

int maxDistance(int* colors, int colorsSize){
   
    return my_max(colors, 0, colorsSize - 1);
}
小结

现在回想起来当时还是太紧张了,因为超时就全盘否定了第一次的做法,其实并没有必要,小改一下就行,保证一定有个边界就好了。

int my_max(int *nums, int s, int t, int length)
{
   
    if (s == t) return 0;
    if (nums[s] != nums[t])
        return t - s;
    else {
   
        int max1 = 0, max2 = 0;
        if (t == length)
			max1 = my_max(nums, s + 1, t, length);
        if (s == 0)
            max2 = my_max(nums, s, t - 1, length);
        return fmax(max1, max2);
    }
}
int maxDistance(int* colors, int colorsSize){
   
    return my_max(colors, 0, colorsSize - 1, colorsSize - 1);
}

第二题

给植物浇水

你打算用一个水罐给花园里的 n 株植物浇水。植物排成一行,从左到右进行标记,编号从 0 到 n - 1 。其中,第 i 株植物的位置是 x = i 。x = -1 处有一条河,你可以在那里重新灌满你的水罐。

每一株植物都需要浇特定量的水。你将会按下面描述的方式完成浇水:

按从左到右的顺序给植物浇水。
在给当前植物浇完水之后,如果你没有足够的水完全浇灌下一株植物,那么你就需要返回河边重新装满水罐。
你不能提前重新灌满水罐。
最初,你在河边(也就是,x = -1),在 x 轴上每移动一个单位都需要 一步 。

给你一个下标从 0 开始的整数数组 plants ,数组由 n 个整数组成。其中,plants[i] 为第 i 株植物需要的水量。另有一个整数 capacity 表示水罐的容量,返回浇灌所有植物需要的步数。

分析

模拟。模拟整个过程,用 sum 表示走过的步数,water 表示当前剩余的水量,循环数组模拟浇水。

int wateringPlants(int* plants, int plantsSize, int capacity){
   
    int sum = 0;
    int water = capacity;
    for (int i = 0; i < plantsSize; i++) {
   
        // 水够就走一步,然后浇水
        if (water >= plants[i]) {
   
            sum += 1;
            water -= plants[i];
        }
        // 不够就回去装水然后再来
        else {
   
            sum += 2 * i;
            water = capacity;
            // for循环默认都会走一步,但是这个水没浇,怎么能走呢
            // 既然默认走一步,那我就先退一步,用while会好一些
            i--;
        }
    }
    return sum;
}

第三题

区间内查询数字的频率

请你设计一个数据结构,它能求出给定子数组内一个给定值的频率 。

子数组中一个值的频率指的是这个子数组中这个值的出现次数。

请你实现 RangeFreqQuery 类:

  • RangeFreqQuery(int[] arr) 用下标从 0 开始的整数数组 arr 构造一个类的实例。
  • int query(int left, int right, int value) 返回子数组 arr[left...right]value 的 频率 。

一个子数 指的是数组中一段连续的元素。arr[left...right] 指的是 nums 中包含下标 leftright 在内的中间一段连续元素。

提示:

  • 1 <= arr.length <= 105
  • 1 <= arr[i], value <= 104
  • 0 <= left <= right < arr.length
  • 调用 query 不超过 10^5 次。
输入:
["RangeFreqQuery", "query", "query"]
[[[12, 33, 4, 56, 22, 2, 34, 33, 22, 12, 34, 56]], [1, 2, 4], [0, 11, 33]]
输出:
[null, 1, 2]

解释:
RangeFreqQuery rangeFreqQuery = new RangeFreqQuery([12, 33, 4, 56, 22, 2, 34, 33, 22, 12, 34, 56]);
rangeFreqQuery.query(1, 2, 4); // 返回 1 。4 在子数组 [33, 4] 中出现 1 次。
rangeFreqQuery.query(0, 11, 33); // 返回 2 。33 在整个子数组中出现 2 次。
分析

沉下心来,好好看懂题目。示例的第一行没什么用,告诉我们第一个是数组,后面都是查询(格式是 left , right , value)。意思就是题目给我们一个数组,我们可以自定义一个数据结构来存储,以便最有利于后面的查找。然后查找 left 和 right 之间的 value 的个数,会查找很多次。

思路

简简单单用个结构体数组,把下标和 value 存入结构体。然后对 value 排序,手写归并,这样是稳定的排序,那么下标也是有序的。然后每次查询的时候,二分找到第一个等于 value 的值和最后一个等于 value 的值,在这两个值之间二分查找第一个下标大于等于 left 的值和最后一个下标小于等于 right 的值。相减就是最终结果。

别人十行能解决,我要100行,属实是很废物了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值