【备战秋招】每日一题:3月18日美团春招第二题:题面+题目思路 + C++/python/js/Go/java 带注释

2023大厂笔试模拟练习网站(含题解)

www.codefun2000.com
最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据,挂载到我们的OJ上,供大家学习交流,体会笔试难度。现已录入200+道互联网大厂模拟练习题,还在极速更新中。欢迎关注公众号“塔子哥学算法”获取最新消息。
在这里插入图片描述
提交链接:

https://codefun2000.com/p/P1088

为了更好的阅读体检,可以查看OJ上的题解。进入提交链接,点击右边菜单栏的"查看塔子哥的题解"

目录

1.题面

2.思路

3.类似题目推荐

4.代码

题面

塔子哥是一名设计师,最近接到了一项重要任务:设计一个新款的生日蜡烛,以庆祝公司成立20周年。为了使蜡烛看起来更加炫目,塔子哥计划在蜡烛上缠绕彩带。他买了一串长度为 N N N 的非常漂亮的彩带,每一厘米的彩带上都是一种色彩,但是当他拿到彩带后才发现,彩带上的颜色太多了,超出了他设计中所需要的颜色种类数量。

于是,塔子哥决定从彩带上截取一段,使得这段彩带上的颜色种类不超过 K K K种。但是,他希望这段彩带尽量长,这样才能在蜡烛上缠绕出更加炫目的效果。为了尽快完成设计,他来找你求助,希望你能帮他设计出一种截取方法,使得截取出来的彩带尽可能长,并且颜色种类不超过 K K K种。

输入描述

第一行两个整数 N , K N,K N,K,以空格分开,分别表示彩带有 N N N厘米长,你截取的一段连续的彩带不能超过 K K K种颜色。接下来一行 N N N个整数,每个整数表示一种色彩,相同的整数表示相同的色彩。

1 ≤ N , K ≤ 5000 1≤N,K≤5000 1N,K5000,彩带上的颜色数字介于 [ 1 , 2000 ] [1,2000] [1,2000]之间

输出描述

一行,一个整数,表示选取的彩带的最大长度。

样例 1 1 1

输入

8 3
1 2 3 2 1 4 5 1

输出

5

说明:

最长的一段彩带是 [ 1 , 2 , 3 , 2 , 1 ] [1,2,3,2,1] [12321],共 5 5 5厘米。

思路

step1:双指针

分析:题目要求满足性质:区间内颜色种类不超过 k k k的 最长区间。所以假设固定左端点,右端点从左往右移动的过程中,性质是先满足,后不满足。即性质满足单调性 。一切满足单调性的问题都能用双指针解决。

如何维护上述性质:

1,我们对当前区间维护一个桶来记录每个值出现的次数(可以使用数组或者哈希表来实现)。

2.在右端点移动的过程中,如果新增的这个数没在桶出现过,那么区间种类数+1。

3.在左端点移动的过程中,如果删去的这个数在桶中恰好只出现一次,那么区间种类数-1.

由此,我们就能够正确的维护区间种类数 , 通过它来判断区间合法性。

类似题目推荐

leetcode

  1. 167. 两数之和 II - 输入有序数组
  2. 344. 反转字符串
  3. 283. 移动零
  4. 11. 盛最多水的容器
  5. 剑指 Offer 48. 最长不含重复字符的子字符串
  6. 209. 长度最小的子数组
  7. 493. 翻转对 (难度较高,需要掌握归并排序等高级算法)

CodeFun2000

P1001-华为Od-k优雅阈值

P1007-58同城-2022.11.5-找出符合条件的子字符串

P1071-百度-2023.3.7-第二题-排列数量

代码实现

Python

from collections import defaultdict
# 读入
n , k = list(map(int , input().split()))
a = list(map(int , input().split()))
res = 0
i = 0
j = 0
# 记录每个数出现次数
num_count = defaultdict(int)
# 记录当前区间的不同数的个数
dif = 0
# 双指针 , i 是左端点 , j 是右端点
while j < n:
    #将a[j]放入桶中
    num_count[a[j]] += 1
    # 如果a[j] 从未出现过,则种类++
    if num_count[a[j]] == 1:
        dif += 1
    # 不满足性质,则收缩左端点
    while dif > k:
        # a[i] 出现一次,那么收缩之后没出现,那么种类数--
        if num_count[a[i]] == 1:
            dif -= 1
        num_count[a[i]] -= 1
        i += 1
    # 到这里,我们就获得了<右端点以j为结尾的,最左的,满足性质的左端点i>. 记录答案
    res = max(res , j - i + 1)
    j += 1
print (ans)

C++

#include <iostream>
#include <unordered_map> // 引入无序哈希映射库 
using namespace std;

int main() {
    int n, k;
    // 读入n和k
    cin >> n >> k; 
    // 开辟数组a,长度为n,存储已经读入的数组元素
    int* a = new int[n]; 
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    // 变量res表示当前的答案,i和j分别是左右指针,dif表示当前区间不同数字的个数
    int res = 0, i = 0, j = 0, dif = 0; 
    // 声明一个哈希映射num_count,存储每个数字出现的次数
    unordered_map<int, int> num_count; 
    // 在哈希映射中将a[j]出现的次数加1
    while (j < n) {
        num_count[a[j]]++; 
        // 如果a[j]之前没有出现过
        if (num_count[a[j]] == 1) { 
            // 区间内不同数字的数量+1
            dif++; 
        }
        // 如果区间内不同数字的数量>dif,说明不能满足性质,需要将区间收缩
        while (dif > k) { 
             // 如果a[i]只出现过一次
            if (num_count[a[i]] == 1) {
                // 区间内不同数字的数量-1
                dif--; 
            }
            // 在哈希映射中将a[i]出现的次数减1
            num_count[a[i]]--; 
            // 左指针i右移(收缩)
            i++; 
        }
        // 更新答案,即记录当前区间长度
        res = max(res, j - i + 1); 
        // 右指针j右移
        j++; 
    }
    // 输出当前的答案
    cout << res << endl; 
    // 释放数组a占用的内存
    delete[] a; 
    return 0;
}

Java

import java.util.Scanner;
import java.util.HashMap;

class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();

        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }

        int res = 0, i = 0, j = 0, dif = 0;
        HashMap<Integer, Integer> num_count = new HashMap<>();

        while (j < n) {
            int cur = a[j];
            num_count.put(cur, num_count.getOrDefault(cur, 0) + 1);
            // 如果a[j]从未出现过,则种类++
            if (num_count.get(cur) == 1) { 
                dif++;
            }
            // 不满足性质,则收缩左端点
            while (dif > k) { 
                int c = a[i];
                // a[i]出现一次,则种类数--
                if (num_count.get(c) == 1) { 
                    dif--;
                }
                num_count.put(c, num_count.get(c) - 1);
                i++;
            }
            // 记录答案
            res = Math.max(res, j - i + 1); 
            j++;
        }

        System.out.println(res);
    }
}

Js

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
    input += data;
    return;
});
process.stdin.on('end', () => {
    const lines = input.trim().split('\n');
    let [n, k] = lines[0].trim().split(' ').map(Number);
    let a = lines[1].trim().split(' ').map(Number);

    let res = 0;
    let i = 0;
    let j = 0;
    // 记录每个数出现次数
    let numCount = new Map();
    // 记录当前区间的不同数的个数
    let dif = 0;
    // 双指针 , i 是左端点 , j 是右端点
    while (j < n) {
        //将a[j]放入桶中
        numCount.set(a[j], (numCount.get(a[j]) || 0) + 1);
        // 如果a[j] 从未出现过,则种类++
        if (numCount.get(a[j]) === 1) {
            dif += 1;
        }
        // 不满足性质,则收缩左端点
        while (dif > k) {
            // a[i] 出现一次,那么收缩之后没出现,那么种类数--
            if (numCount.get(a[i]) === 1) {
                dif -= 1;
            }
            numCount.set(a[i], numCount.get(a[i]) - 1);
            i += 1;
        }
        // 到这里,我们就获得了<右端点以j为结尾的,最左的,满足性质的左端点i>. 记录答案
        res = Math.max(res, j - i + 1);
        j += 1;
    }
    console.log(res); // 输出答案
});

Go

package main

import "fmt"

func main() {
    var n, k int
    fmt.Scan(&n, &k)
    a := make([]int, n)
    for i := 0; i < n; i++ {
        fmt.Scan(&a[i])
    }

    numCount := make(map[int]int)
    res, i, j, dif := 0, 0, 0, 0
    for j < n {
        cur := a[j]
        numCount[cur]++
        if numCount[cur] == 1 { // 如果a[j]从未出现过,则种类++
            dif++
        }

        for dif > k { // 不满足性质,则收缩左端点
            c := a[i]
            if numCount[c] == 1 {  // a[i]出现一次,则种类数--
                dif--
            }
            numCount[c]--
            i++
        }

        res = max(res, j-i+1) // 记录答案
        j++
    }

    fmt.Println(res)
}

func max(a, b int) int { // 自定义max函数
    if a > b {
        return a
    }
    return b
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

塔子哥学算法

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

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

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

打赏作者

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

抵扣说明:

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

余额充值