【2024】【字节青训营】:字节青训营入营测试题

目录

简单题目

2 计算x到y的最小步数

4 环状 DNA 序列整理

13 Base32 解码和编码

28 打点计时器

64 兔生兔

67 完美整数

96 找出整数数组中占比超过 1 / N 的数(应该是一半吧)

97 找出最长的神奇数列

98 找单独的数

100 字符串最短循环子串

中等题目

5 简单四则运算

7 字符串有多少种可能性

50 迷人的子序列

58 五子棋获胜策略

困难题目

8 进制求和转换

27 查找热点数据



【✍️ 入营考核】AI 加码,青训营 X 豆包MarsCode 技术训练营👏 欢迎各位同学报名“AI 加码,青训营 X - 掘金 (juejin.cn)

要求:

简单题不少于10道题

中等题目不少于4道题

困难题目不少于1道题

介绍:

本次24青训营,入营和之前的考核模型有所不同,之前是做题,几十个选择题,两道算法题,一道简答题,现在则是在ai的辅助下进行刷题考核,这么做的原因无非是推广自己家的智能编码助手,还有就是此次代码考核在在线平台上,就能得到大量的数据,然后使用这些数据去强化编码助手,最后就是ai助手有点傻,一个是你把他给你的代码,都过不了示例,然后他容易顺着你代码的想法,往后推理,如果你一开始的想法不对,就会进入死角。

下面是我的刷题笔记,都是通过了示例,但是具体能不过AC,未知。

简单题目

已完成 10

2 计算x到y的最小步数

# 问题描述

AB 实验同学每天都很苦恼如何可以更好地进行 AB 实验,每一步的流程很重要,我们目标为了缩短所需的步数。

我们假设每一步对应到每一个位置。从一个整数位置 `x` 走到另外一个整数位置 `y`,每一步的长度是正整数,每步的值等于上一步的值 `-1`, `+0`,`+1`。求 `x` 到 `y` 最少走几步。并且第一步必须是 `1`,最后一步必须是 `1`,从 `x` 到 `y` 最少需要多少步。

## 样例说明

- 整数位置 `x` 为 `12`,另外一个整数位置 `y` 为 `6`,我们需要从 `x` 走到 `y`,最小的步数为:`1`,`2`,`2`,`1`,所以我们需要走 `4` 步。
- 整数位置 `x` 为 `34`,另外一个整数位置 `y` 为 `45`,我们需要从 `x` 走到 `y`,最小的步数为:`1`,`2`,`3`,`2`,`2`,`1`,所以我们需要走 `6` 步。
- 整数位置 `x` 为 `50`,另外一个整数位置 `y` 为 `30`,我们需要从 `x` 走到 `y`,最小的步数为:`1`,`2`,`3`,`4`,`4`,`3`,`2`,`1`,所以我们需要走 `8` 步。

## 输入格式

输入包含 `2` 个整数 `x`,`y`。(`0<=x<=y<2^31`)

## 输出格式

对于每一组数据,输出一行,仅包含一个整数,从 `x` 到 `y` 所需最小步数。

## 输入样例

```
12 6
34 45
50 30
```

## 输出样例

```
4
6
8
```

问题分析:

从x走到y,其实就是从步伐大小从1开始走,最后一步也必须为1,每一步之间呢,可以+1,0,和-1,如果说想要最小步数,这个步伐肯定要迈的大,我的代码呢,遵循一个原则,就是第一步肯定为1,接下来每一步有三种选择,假设步伐为x,一个是x + 1,一个是x,一个是x - 1,在优先级上x + 1 > x > x - 1,在是否合规上采取走下一步的时候,必须保证剩余的距离,可以降到 1 ,也就是说先 x + 1,但是剩下的距离必须大于等于 x~1的和,如果不可以那就尝试 x,剩下的距离大于等于 x - 1 ~ 1 的he,x - 1也是如此,直至走到y。

代码如下:

#include <iostream> 
using namespace std;
#include <cmath> 

int sum(int x){
    if(x <= 0){
        return 0;
    }
    int res = 0;
    for(int i = 1; i <= x; i ++){
        res = res + i;
    }

    return res;
}
 
// 计算从x到y的最少步数 
int minSteps(int x, int y) { 
    if(x > y){
        swap(x,y);
    }
    int l = 0, r = y - x;
    int step = 0;
    int stepdistance = 0;
    while(l < r){
        if(step == 0){
            stepdistance = 1;
            step = 1;
            l = l + stepdistance;
            continue;
        }
        int step1 = stepdistance + 1;
        int step2 = stepdistance;
        int step3 = stepdistance - 1;
        if(l + step1 < r){
            int m = l + step1;
            int s = sum(step1 - 1);
            if((r - m) >= s){
                l = m;
                step ++;
                stepdistance = step1;
                continue;
            }
        }
        if( l + step2 <= r){
            int m = l + step2;
            int s = sum(step2 - 1);
            if((r - m) >= s){
                l = m;
                step ++;
                stepdistance = step2;
                continue;
            }
        }
        if( l + step3 <= r){
            int m = l + step3;
            int s = sum(step3 - 1);
            if((r - m) >= s ){
                l = m;
                step ++;
                stepdistance = step3;
                continue;
            }
        }

    }

    return step;

} 
 
 
int main() { 
    std::cout << (minSteps(6, 7) == 1) << std::endl;
    std::cout << (minSteps(12, 6) == 4) << std::endl; 
    std::cout << (minSteps(34, 45) == 6) << std::endl; 
    std::cout << (minSteps(50, 30) == 8) << std::endl; 
    return 0; 
}

运行结果:

4 环状 DNA 序列整理

# 问题描述

环状 DNA 又称超螺旋,即一段碱基序列呈现环状,在分析时,需要将相同序列的环状 DNA 分到相同组内,现需将环状碱基序列按照最小表示法进行排序。

一段长度为 `n` 的碱基序列,按照顺时针方向,碱基序列可以从任意位置起开始该序列顺序,因此长度为 `n` 的碱基序列有 `n` 种表示法。例如:长度为 6 的碱基序列 `CGAGTC`,有 `CGAGTC`、`GAGTCC`、`AGTCCG` 等表示法。在这些表示法中,字典序最小的称为“最小表示”。

输入一个长度为 `n`(`n <= 100`)的环状碱基序列(只包含 `A`、`C`、`G`、`T` 这 4 种碱基)的一种表示法,输出该环状碱基序列的最小表示。

例如:
`ATCA` 的最小表示是 `AATC`
`CGAGTC` 的最小表示是 `AGTCCG`

## 输入描述

一段 DNA 碱基序列

## 输出描述

DNA 碱基序列的最小表示

**备注**:
`n <= 100`
DNA 由大写英文字母 `A`、`G`、`C`、`T` 组成

**示例 1**
输入:`ATCA`
输出:`AATC`

**示例 2**
输入:`CGAGTC`
输出:`AGTCCG`

问题分析:

通过循环将所有的可能存储起来,然后循环比较得出最小的DNA碱基序列

代码如下:

#include <iostream>
using namespace std;
#include <string>
#include <vector>

std::string solution(std::string dna_sequence) {
    // Please write your code here
    vector<string> representations;
    for(int i = 0; i < dna_sequence.size();i++){
        string representation = dna_sequence.substr(i) + dna_sequence.substr(0,i);
        representations.push_back(representation);
    }
    string minRepresentation = representations[0];
    for(auto representation : representations){
        if( representation < minRepresentation){
            minRepresentation = representation;
        }
    }
    return minRepresentation;
}

int main() {
    // You can add more test cases here
    std::cout << (solution("ATCA") == "AATC") << std::endl;
    std::cout << (solution("CGAGTC") == "AGTCCG") << std::endl;
    std::cout << (solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG") == "AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG") << std::endl;
    return 0;
}

运行结果:

13 Base32 解码和编码

# 问题描述

你需要实现一个 Base32 的编码和解码函数。

相比于 Base32,你可能更熟悉 Base64,Base64 是非常常见的用字符串形式表示二进制数据的方式,在邮件附件、Web 中的图片中都有广泛的应用。

Base32 是 Base64 的变种,与 Base64 不同的地方在于 Base64 以 6 bit 为一组作为索引,而 Base32 以 5 bit 为一组作为索引,每一组用一个 ASCII 字符表示。Base 64 总共需要 64 个字符表示,而 Base32 则只需要 32 个字符表示。

Base32 的编码流程如下:
- 对二进制数据进行预处理:如果二进制数据的 bit 数目不不是 5 的倍数的话,在末尾补 0 直至为 5 的倍数
- 以 5 bit 为一组进行分组
- 将每一组的 5 bit 二进制转换为索引(0 - 31)
- 在索引 - 字符转换表中查询索引对应的字符
- 根据原始二进制数据的 bit 数目除以 40 后的余数,确定末尾需要补 0 的数目
  - 如果原始二进制数据 bit 数目除以 40 后的余数是 0 的话,不需要补 +
  - 如果原始二进制数据 bit 数目除以 40 后的余数是 8 的话,补 6 个 +
  - 如果原始二进制数据 bit 数目除以 40 后的余数是 16 的话,补 4 个 +
  - 如果原始二进制数据 bit 数目除以 40 后的余数是 24 的话,补 3 个 +
  - 如果原始二进制数据 bit 数目除以 40 后的余数是 32 的话,补 1 个 +

Base32 的索引 - 字符转换表见下方。

索引:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

字符:9 8 7 6 5 4 3 2 1 0 m  n  b  v  c  x  z  a  s  d  f  g  h  j  k  l  p  o  i  u  y  t

**示例**

**编码**

- 输入:字符串 `foo`
- 字符 `f` 的 ASCII 编号为 102,字符 `o` 的 ASCII 编号为 111
- 将字符串 `foo` 以 ASCII 编号形式表达为 102 111 111 的序列
- 将 102 111 111 的序列转换为二进制表示,即 01100110 01101111 01101111,将二进制字符串以 40 个为一组进行分割
- 最后一组的二进制字符串长度为 24,不是 5 的倍数,因此在最后补 0,直至其能被 5 整除(在此例子中,补 1 个即可),二进制字符串表示为: 01100110 01101111 01101111 0
- 每 5 bit 为一组,表示为:01100 11001 10111 10110 11110
- 将每一组转换为十进制的索引,表示为:12 25 23 22 30,对应字符 `b` `l` `j` `h` `y`
- 由于最终输出字符串长度不是 8 的倍数,在输出最后补充 3 个 `+`
- 查询索引 - 字符转换表后,可以得出最终的输出为:`bljhy+++`

`Input data: foo`
`Input in Unicode: 102 111 111`
`Unicode in binary (8-bit): 01100110 01101111 01101111 0`
`Unicode in binary (5-bit): 01100 11001 10111 10110 11110`
`Decimal: 12 25 23 22 30`
`Pad: + + +`
`Output: b l j h y + + +`

**解码**

- 输入:`bljhy+++`
- 查询索引 - 字符转换表后,可知原始的二进制数据组为:01100 11001 10111 10110 11110
- 由末尾 3 个 `+` 可知在编码时原始二进制数据最后一组的个数为 24 个,由此可知最后一组数据为:01100110 01101111 01101111
- 将二进制数据转换为 ASCII 编号后可知,原始字符串的 Unicode 序列为:102 111 111
- 将 Unicode 序列转换为字符串,即可得出原始字符串,为:`foo`

**输入示例**

`foo`
`b0zj5+++`

- 第一行为需要编码的原始字符串:`rawStr`
- 第二行为需要解码的 Base32 字符串:`encodedStr`

**输出示例**

`bljhy+++`
`bar`

**解释**:
- 第一行编码后的输出为 `bljhy+++`
- 第二行解码后的输出为 `bar`

**数据范围**

`rawStr[n]` 为 ASCII 的可显示字符,`rawStr.length < 2048`
`encodedStr` 为使用此算法编码后的 Base32 字符序列,`encodedStr.length < 4096`

问题分析:

这个题目不是很难,但是很繁琐,可能是我的实现问题的原因,我写了很多函数,

各个函数的作用:

`decimalToBinary8Bits` 用于将十进制数转换为 8 位二进制字符串,

`binaryToDecimal` 用于将二进制字符串按 5 位一组转换为十进制数并存入向量,

`decimalArrayToBinary` 用于将十进制数向量转换为二进制字符串,

`binaryToChar` 用于将二进制字符串按 8 位一组转换为 ASCII 码对应的字符。

`jiema` 函数用于解码操作,通过判断输入字符串末尾的 `+` 个数来确定原始二进制数据的长度,然后进行解码处理。但这个函数中的条件判断较多,可能会增加理解和维护的难度。

`solution` 函数是主要的处理函数,它对输入的原始字符串进行预处理,转换为二进制字符串并根据余数进行补零,然后进行编码和解码操作。

代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <array>
using namespace std;

std::array<char, 32> base32 = {'9', '8', '7', '6', '5', '4', '3', '2', '1', '0', 'm', 'n', 'b', 'v', 'c', 'x', 'z', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'p', 'o', 'i', 'u', 'y', 't'};

std::string decimalToBinary8Bits(int num) {
    std::string binary;
    for (int i = 7; i >= 0; i--) {
        if (num & (1 << i)) {
            binary += '1';
        } else {
            binary += '0';
        }
    }
    return binary;
}

std::vector<int> binaryToDecimal(const std::string& binaryStr) {
    std::vector<int> decimalNums;
    for (size_t i = 0; i < binaryStr.size(); i += 5) {
        std::string group = binaryStr.substr(i, 5);
        int decimal = 0;
        for (char c : group) {
            decimal = decimal * 2 + (c - '0');
        }
        decimalNums.push_back(decimal);
    }
    return decimalNums;
}

std::string decimalArrayToBinary(const std::vector<int>& arr) {
    std::string result;
    for (const auto& num : arr) {
        std::string binary;
        int n = num;
        for (int i = 4; i >= 0; i--) {
            if (n & (1 << i)) {
                binary += '1';
            } else {
                binary += '0';
            }
        }
        result += binary;
    }
    return result;
}

std::string binaryToChar(const std::string& binaryStr) {
    std::string result;
    for (size_t i = 0; i < binaryStr.size(); i += 8) {
        std::string group = binaryStr.substr(i, 8);
        int decimal = 0;
        for (char c : group) {
            decimal = decimal * 2 + (c - '0');
        }
        result += static_cast<char>(decimal);
    }
    return result;
}

string jiema(string encodedStr){
    int i = 0;
    for(i = encodedStr.size() - 1; i > 0 && encodedStr[i] == '+'; i --);
    string newstr = encodedStr.substr(0,i + 1);
    vector<int> st2;
    for(int i = 0; i < newstr.size(); i ++){
        for(int j = 0; j < base32.size(); j ++){
            if(newstr[i] == base32[j]){
                st2.push_back(j);
            }
        }
    }
    string newnewstr = decimalArrayToBinary(st2);
    string res2 = "";
    if(newnewstr.size() % 40 == 10){
        string newstrs = newnewstr.substr(0,newnewstr.size() - 2);
        res2 = binaryToChar(newstrs);
    }else if(newnewstr.size() % 40 == 20){
        string newstrs = newnewstr.substr(0,newnewstr.size() - 4);
        res2 = binaryToChar(newstrs);
    }else if(newnewstr.size() % 40 == 25){
        string newstrs = newnewstr.substr(0,newnewstr.size() - 1);
        res2 = binaryToChar(newstrs);
    }else if(newnewstr.size() % 40 == 35){
        string newstrs = newnewstr.substr(0,newnewstr.size() - 3);
        res2 = binaryToChar(newstrs);
    }

    return res2;
}

std::string solution(std::string rawStr, std::string encodedStr) {
    // Please write your code here
    
    vector<int> st;
    string str1 = "";
    for(int i = 0; i < rawStr.size();i++){
        str1 += decimalToBinary8Bits(static_cast<int>(rawStr[i]));
    }
    int r = str1.size() % 40;
    if(r == 8){
        str1 += "00";
    }else if(r == 16){
        str1 += "0000";
    }else if(r == 24){
        str1 += "0";
    }else if(r == 32){
        str1 += "000";
    }

    st = binaryToDecimal(str1);
    string res1 = "";
    for(int i = 0; i < st.size() ; i ++){
        res1 += base32[st[i]];
    }
    while( res1.size() % 8 != 0){
        res1 += "+";
    }
    string res2 = "";
    for(int i = 0; i < encodedStr.size(); i += 8){
        res2 += jiema(encodedStr.substr(i,i + 8));
    }

    
    //cout << res1 << endl;
    //cout << res2 << endl;

    return res1 + ":" +  res2;
}

int main() {
    // You can add more test cases here
    std::cout << (solution("foo", "b0zj5+++") == "bljhy+++:bar") << std::endl;
    std::cout << (solution("The encoding process represents 40-bit groups of input bits as output strings of 8 encoded characters.  Proceeding from left to right, a 40-bit input group is formed by concatenating 5 8bit input groups. These 40 bits are then treated as 8 concatenated 5-bit groups, each of which is translated into a single character in the base 32 alphabet.  When a bit stream is encoded via the base 32 encoding, the bit stream must be presumed to be ordered with the most-significant- bit first. That is, the first bit in the stream will be the high- order bit in the first 8bit byte, the eighth bit will be the low- order bit in the first 8bit byte, and so on.", "bljhy+++b0zj5+++") == "maf3m164vlahyl60vlds9i6svuahmiod58l3mi6sbglhmodfcbz61b8vb0fj1162c0jjmi6d58jhb160vlk2mu89b0fj1il9b4ls9oogcak2mu89cvp25pncbuls9oo359i79lncbvjh1ln558ahzknsb4aj1lnscbj7917zc0jh3ln4bafhill9bll3yo09vashbu89cajs9id0buf21n89b5z61b8vb0fj1160vlk2mu89bul3yunz58fj3163vul3pln558a2s166vuj33knfbgj37u60vlds9v0928a3su89v4j29unf58dj5oogc8lsi17fv8sj3l093zk79kd0cals9knsbfz21p64vkz21id4b4p3ml89b4ls9c89bvjhiko8cashiknfbgs79v0vb0fj1162c0jjmi6d4zz3mkn6v9z3yla9cuf3sko158fj316fc0zhiiobb4p3ml89v4j21ol9b5z23pncbuh3m166v8zj5kn6casj5160vkz21p6458a37io459ld5168vak3zkn7bgp7i189muf3moa9b5z35pnf58lj1id4b4hs9pnd58shikoxbash116hv4zs9u61bfz35kndbfz63ba9bgj33oo5v4j3cn89caf3m167v4p79iofc0sh7o09vgpj3u89b0ss9i6sbgljmon4bzz21ol9b0ss9oosbasj5ln558ohsu6158p3zl09vgjj3u8vcvfhcod0blfh3kncczhs9kd0czz3bpnscvp7i17fv8zj1160cbh79u61bfz3bpnscvp79kd0czz3soa9caf3m16dcal3mknv58ohso6b58a3m16fv8ss9p60buf7p16xc0s3mia9b0fj1160vkz21p6458d3siddczz6zkd0czz35ynfbfh79u61bfz3mpn2v8p3z167v4p79uo0vah79kd458p3zl09vajjcn09vul31lns58a3su89v4j79u61bfz3bpnscvp79c67v4p79kdlcassk168vls79iox58jhinz+:foobar") << std::endl;
    return 0;
}

运行结果:

28 打点计时器

# 问题描述

小明想发明一台打点计数器,这个计数器有这样的一个功能:

- 它可以接收一个递增的数据范围(形如[3, 9]),其中第一个数字代表起始,第二个数字代表结束

- 这个数据范围中包含几个数字,打点计数器就会打几个点

- 在传入的多组数据范围中,如果出现了范围的重复,机器则不会重复打点

你可以帮助小明算一算,在不同的情况下,计数器会打出几个点么?

## 输入格式

一个二维数组

## 输出格式

一个整数,表达在输入是这个数组的情况下,计数器打出的点数

**输入样例(1)**

[
   [1,4],
   [7, 10],
   [3, 5]
]

**输出样例(1)**

7

**输入样例(2)**

[
   [1,2],
   [6, 10],
   [11, 15]
]

**输出样例(2)**

9

**数据范围**

- 数字范围 [-10^9, 10^9],数组长度 < 2^16

问题分析:

本题目采用集合来处理,因为集合具有互异性,所以在打点过程中重复区域的会被去掉,遍历每段区间,区间遍历每个点,存进集合中,最后返回集合的大小就是打点的数量

代码如下:

#include <iostream>
#include <vector>
#include <set>
using namespace std;

int solution(std::vector<std::vector<int>> inputArray) {
    // Please write your code here
    set<int> myset;
    for(auto x : inputArray){
        for(int i = x[0];i < x[1]; i++){
            myset.insert(i);
        }
    }
    return myset.size();
}

int main() {
    //  You can add more test cases here
    std::vector<std::vector<int>> testArray1 = {{1, 4}, {7, 10}, {3, 5}};
    std::vector<std::vector<int>> testArray2 = {{1, 2}, {6, 10}, {11, 15}};

    std::cout << (solution(testArray1) == 7) << std::endl;
    std::cout << (solution(testArray2) == 9) << std::endl;

    return 0;
}

运行结果:

64 兔生兔

# 问题描述
- 如果一对兔子每月生一对兔子;一对新生兔,从第二个月起就开始生兔子;假定每对兔子都是一雌一雄,试问一对兔子,第 `n` 个月能繁殖成多少对兔子?(举例,第1个月是1对兔子,第2个月是2对兔子)

## 输入格式
- 数字

## 输出格式
- 数字

## 输入样例
- 5

## 输出样例
- 8

## 数据范围
- `[1, 75]`

## 测试数据集
  - 样例1
    - 输入:`5`
    - 输出:`8`
  - 样例2
    - 输入:`1`
    - 输出:`1`
  - 样例3
    - 输入:`15`
    - 输出:`987`
  - 样例4
    - 输入:`50`
    - 输出:`20365011074`

问题分析:

  1. 函数定义:
    • int solution(int n):这个函数接受一个整数 n 作为输入,并返回第 n 个月兔子的对数。
  1. 基本情况处理:
    • 如果 n 是 1 或 2,函数直接返回 1 或 2,这是斐波那契数列的前两个数(或在这个问题中,第一个月和第二个月的兔子对数)。
  1. 动态规划数组:
    • vector<int> dp(n + 1):创建了一个大小为 n + 1 的动态规划数组 dp,用于存储从第 1 个月到第 n 个月的兔子对数。
    • dp[1] = 1dp[2] = 2:初始化前两个月的兔子对数。
  1. 递推公式:
    • for (int i = 3; i <= n; i++):从第 3 个月开始,使用递推公式 dp[i] = dp[i - 1] + dp[i - 2] 计算每个月的兔子对数。这个公式基于斐波那契数列的定义,即每个数都是前两个数的和。
  1. 返回结果:
    • return dp[n]:返回第 n 个月的兔子对数

代码如下:

#include <iostream>  
using namespace std;  
#include <vector>


int solution(int n) {
    // 使用动态规划来保存前两个月的兔子对数
    if (n == 1) return 1; // 第一个月
    if (n == 2) return 2; // 第二个月

    vector<int> dp(n + 1); // dp[i] 表示第 i 个月的兔子对数
    dp[1] = 1; // 第一个月
    dp[2] = 2; // 第二个月

    // 计算每个月的兔子对数
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2]; // 递推公式
    }

    return dp[n]; // 返回第 n 个月的兔子对数
}



  
int main() {  
    // 验证输出结果是否符合预期  
    cout << (solution(5) == 8) << endl;  
    cout << (solution(1) == 1) << endl;  
    cout << (solution(15) == 987) << endl;  
    //cout << (solution(50) == 20365011074) << endl; 
  
    return 0;  
}

运行结果:

67 完美整数

# 问题描述
一个整数如果由相同数字构成,可以称为完美整数;比如说1、11、333就是完美整数,12、19、101就是不完美的整数。
现在想知道,在区间 `[x, y]` 中有多少个整数是完美整数。

## 输入格式
每个样例有一行,是整数 `x` 和 `y`;(1 ≤ x ≤ y ≤ 10^9)

## 输出格式
每一个样例一行,是整数 `m`,表示区间 `[x, y]` 中有 m 个整数是完美整数。

## 输入样例1
1 10  

## 输出样例1

9  

## 输入样例2
2 22


## 输出样例2
10

## 数据范围

1 ≤ t ≤ 1000
1 ≤ x ≤ y ≤ 10^9

问题分析:

其实生成了10^9之内的所有完美整数,然后对这些完美整数进行排序,然后计算完美整数的左右区间,通过区间得到完美整数的数量

代码如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 生成所有不超过 10^9 的完美整数
vector<long long> generatePerfectNumbers() {
    vector<long long> perfectNumbers;
    for (int digit = 1; digit <= 9; ++digit) {  // 从 1 到 9 
        long long perfectNumber = digit;
        while (perfectNumber <= 1000000000) {  // 直接通过循环累加构建完美整数
            perfectNumbers.push_back(perfectNumber);
            perfectNumber = perfectNumber * 10 + digit;
        }
    }
    return perfectNumbers;
}

vector<long long> perfectNumbers = generatePerfectNumbers();


int solution(long long x, long long y) {
    auto left = lower_bound(perfectNumbers.begin(), perfectNumbers.end(), x);  // 找到第一个大于等于 x 的位置
    auto right = upper_bound(perfectNumbers.begin(), perfectNumbers.end(), y);  // 找到第一个大于 y 的位置
    // 计算区间内完美整数的个数
    return right - left;  
}

int main() {
    sort(perfectNumbers.begin(), perfectNumbers.end());
    std::cout << (solution(1, 10) == 9) << std::endl;
    std::cout << (solution(2, 22) == 10) << std::endl;
    return 0;
}

运行结果:

96 找出整数数组中占比超过 1 / N 的数(应该是一半吧)

## 问题描述
- 给定一个长度为n的整型数组,已知其中一个数字的出现次数超过数组长度的一半,找出这个元素

## 输入格式
- 一个长度为n的数组,其中某个元素的出现次数大于n/2

## 输出格式
- 一个整数

## 输入样例
- [1,3,8,2,3,1,3,3,3]

## 输出样例
- 3

## 数据范围
- 任意长度为n整数数组,其中某个元素的出现次数大于n/2

问题分析:

其实就是找出出现次数超过一半的数,首先通过快排将数组拍成有序的,然后取有序的中间那个数就可以,因为是大于一半的,就算是极限情况从头或者从尾开始,中间那个数也是出现一半以上的,更不用说其他在中间的情况了

代码如下:

#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;

// 正确的快速排序函数
void quickSort(int l, int r, vector<int>& num) {
    if (l >= r) return;
    int mid = num[(l + r) / 2];  // 修改基准元素的选取
    int i = l - 1, j = r + 1;
    while (i < j) {
        do i++; while (num[i] < mid);
        do j--; while (num[j] > mid);
        if (i < j)  swap(num[i], num[j]);
    }
    quickSort(l, j, num);
    quickSort(j + 1, r, num);
}

// 修改后的求解函数,返回出现次数超过一半的元素
int solution(vector<int> list) {
    quickSort(0, list.size() - 1, list);
    
    return list[(list.size() - 1) / 2];  
}

int main() {
    // Add your test cases here

    cout << (solution({1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3) << endl;

    return 0;
}

运行结果:

97 找出最长的神奇数列

# 问题描述

小明是一个中学生,今天他刚刚学习了数列。他在纸上写了一个长度为 `n` 的正整数序列,$a_0,a_1,\ldots,a_{n-1}$。这个数列里面只有 1 和 0,我们将 1 和 0 没有重复跟随并且至少由 3 个数组成的数列的数列称之为「神奇数列」。比如 `10101` 是一个神奇数列,`1011` 不是一个神奇数列。他想知道这个序列里面最长的「神奇数列」是哪个,你可以帮帮他吗?

## 输入格式

- 一行连续的数 `s`,只有 `0` 和 `1`

## 输出格式

- 一行数

## 输入样例


0101011101


## 输出样例


010101


## 数据范围

- $1 < s.length \leq 5 \times 10^4$

问题分析:

通过遍历字符串,如果相邻的不同,就长度增加,如果相同了,就把相同之前的不同的一个串尝试更新的最长神奇数列,首先要长度大于3,其次要和之前的生气数列比较,最后返回字符串

代码如下:

#include <iostream>
#include <string>
using namespace std;

std::string solution(const std::string& inp) {
    string maxlist; // 用于存储最长的神奇数列
    int maxLength = 0; // 最长神奇数列的长度
    int n = inp.size(); // 输入字符串的长度

    // 当前神奇数列的起始位置和长度
    int start = 0;
    int currentLength = 1;

    for (int i = 1; i < n; i++) {
        if (inp[i] != inp[i - 1]) { // 当前字符与前一个字符不同
            currentLength++; // 更新当前神奇数列的长度
        } else {
            // 如果当前长度大于等于3,检查是否需要更新最长的神奇数列
            if (currentLength >= 3) {
                string candidate = inp.substr(start, currentLength);
                if (currentLength > maxLength) {
                    maxLength = currentLength;
                    maxlist = candidate; // 更新最长神奇数列
                }
            }
            // 重置当前神奇数列
            start = i;
            currentLength = 1; // 重新计数
        }
    }

    // 处理最后一段神奇数列
    if (currentLength >= 3) {
        string candidate = inp.substr(start, currentLength);
        if (currentLength > maxLength) {
            maxlist = candidate; // 更新最长神奇数列
        }
    }

    return maxlist; // 返回最长的神奇数列
}

int main() {
    // Add your test cases here
    
    std::cout << (solution("0101011101") == "010101") << std::endl;
    return 0;
}

运行结果:

98 找单独的数

# 问题描述
有一堆数字,除了一个数字,其它的数字都是成对出现。班上的每个同学拿一个数字,正好将这些数字全部拿完,问如何快速找到拿了单独数字的同学?

## 输入格式
- 空格分隔输入所有的数字

## 输出格式
- 单独的那个数字

## 输入样例(1)
```
1 1 2 2 3 3 4 5 5
```
## 输出样例(1)
4

## 输入样例(2)
```
0 1 0 1 2
```
## 输出样例(2)
2

问题分析:

这个应该是100个题目中最简单的一个了,通过异或会把相同的数字抵消掉,剩下的就是那个单独的数字。

代码如下:

#include <iostream>
#include <vector>

int solution(std::vector<int> inp) {
    // Edit your code here
    int res = 0;
    for(int i = 0; i < inp.size(); i ++){
        res ^= inp[i];
    }
    return res;
}

int main() {
    // Add your test cases here
    
    std::cout << (solution({1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4) << std::endl;
    std::cout << (solution({0, 1, 0, 1, 2}) == 2) << std::endl;
    
    return 0;
}

100 字符串最短循环子串

# 问题描述
- 输入一个字符串,判断其是否完全循环,若是循环的,输出最短的循环子串,否则输出空`""`
- 如输入 `abababab`,输出 `ab`;输入 `ab` 则输出 `""`

## 输入格式
- 合法字符串 如 `abcabcabcabc` `aaa`

## 输出格式
- 最短的循环子串 `"abc"` `"a"`

## 输入样例
- `"abcabcabcabc"`

## 输出样例
- `"abc"`

## 数据范围
测试数据集

问题分析:

首先将每一种可能的字符串切出来,然后通过循环比较,字串通过取余循环,来判断是否为循环字串,如果j走到了最后,那么当前的字串就是他的循环字串,因为是从小的串开始,如果j走到了最后那么就不会切更大的字串直接跳出循环,保证了是最小的字串,如果i走到最后还没有找到,那么结果就是“”。

代码如下:

#include <iostream>
#include <string>
using namespace std;

std::string solution(const std::string &inp) {
    // Edit your code here
    string str = "";
    int i = 0, j = 0 , k = 0;
    for(i = 0; i < inp.size(); i ++){
        str = inp.substr(0,i + 1);//切串
        for(j = i + 1 , k = 0; j < inp.size() ; j ++ , k ++){
            if(inp[j] != str[k %(i + 1)]){ //比较
                break;
            }
        }
        if(j == inp.size()){
            break;
        }
    }
    if(i == inp.size()){
        return "";
    }
    return str;
}

int main() {
    // Add your test cases here
    
    std::cout << (solution("abcabcabcabc") == "abc") << std::endl;
    return 0;
}

运行结果:

中等题目

已完成 4

5 简单四则运算

# 问题描述

实现一个基本的计算器来计算一个简单的字符串表达式的值。注意事项如下:

- 输入是一个字符串表达式(可以假设所给定的表达式都是有效的)

- 字符串表达式可以包含的运算符号为:左括号 `(`, 右括号 `)`, 加号 `+`, 减号 `-`

- 可以包含的数字为:非负整数(< 10)

- 字符串中不包含空格

- 处理除法 case 的时候,可以直接省略小数部分结果,只保留整数部分参与后续运算

- 请不要使用内置的库函数 `eval`

## 输入格式

如:`3+4*5/(3+2)`

## 数据约束

见题目描述

## 输出格式

计算之后的数字

**输入样例**:
- `1+1`
- `3+4*5/(3+2)`
- `4+2*5-2/1`
- `(1+(4+5+2)-3)+(6+8)`

**输出样例**:
- `2`
- `7`
- `12`
- `23`

问题分析:

其实这是一道数据结构的题目,如果仔细学过数据结构或者考研考过,这是栈的应用,通过符号的优先级来确定入栈还是出栈,最后留在栈里的就是结果。

代码如下:

#include <iostream>  
#include <stack>  
#include <string>  
#include <cctype>  
  
using namespace std;  
  
int precedence(char op) {  
    if (op == '+' || op == '-') {  
        return 1;  
    }  
    if (op == '*' || op == '/') {  
        return 2;  
    }  
    return 0;  
}  
  
int applyOp(int a, int b, char op) {  
    switch (op) {  
        case '+': return a + b;  
        case '-': return a - b;  
        case '*': return a * b;  
        case '/': return a / b;  // 直接取整数部分结果  
    }  
    return 0;  
}  
  
int evaluate(const string& tokens) {  
    stack<int> values;  
    stack<char> ops;  
    for (size_t i = 0; i < tokens.length(); ++i) {  
        // 跳过空格  
        if (isspace(tokens[i])) {  
            continue;  
        }  
  
        // 当前字符是数字,则解析完整的数字  
        if (isdigit(tokens[i])) {  
            int val = 0;  
            while (i < tokens.length() && isdigit(tokens[i])) {  
                val = (val * 10) + (tokens[i] - '0');  
                ++i;  
            }  
            --i;  // 补偿最后多加的一次递增  
            values.push(val);  
        }  
        // 当前字符是左括号,直接压入运算符栈  
        else if (tokens[i] == '(') {  
            ops.push(tokens[i]);  
        }  
        // 当前字符是右括号,处理栈中的运算符直到遇到左括号  
        else if (tokens[i] == ')') {  
            while (!ops.empty() && ops.top() != '(') {  
                int val2 = values.top();  
                values.pop();  
  
                int val1 = values.top();  
                values.pop();  
  
                char op = ops.top();  
                ops.pop();  
  
                values.push(applyOp(val1, val2, op));  
            }  
            // 弹出左括号  
            if (!ops.empty()) {  
                ops.pop();  
            }  
        }  
        // 当前字符是运算符  
        else {  
            while (!ops.empty() && precedence(ops.top()) >= precedence(tokens[i])) {  
                int val2 = values.top();  
                values.pop();  
  
                int val1 = values.top();  
                values.pop();  
  
                char op = ops.top();  
                ops.pop();  
  
                values.push(applyOp(val1, val2, op));  
            }  
            ops.push(tokens[i]);  
        }  
    }  
  
    // 处理栈中剩余的运算符  
    while (!ops.empty()) {  
        int val2 = values.top();  
        values.pop();  
  
        int val1 = values.top();  
        values.pop();  
  
        char op = ops.top();  
        ops.pop();  
  
        values.push(applyOp(val1, val2, op));  
    }  
  
    // 栈中应该只剩下一个值,即表达式的计算结果  
    return values.top();  
} 

int main() {
    // You can add more test cases here
    std::cout << (evaluate("1+1") == 2) << std::endl;
    std::cout << (evaluate("3+4*5/(3+2)") == 7) << std::endl;
    std::cout << (evaluate("4+2*5-2/1") == 12) << std::endl;
    std::cout << (evaluate("(1+(4+5+2)-3)+(6+8)") == 23) << std::endl;
    return 0;
}

运行结果:

7 字符串有多少种可能性

# 问题描述

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

## 输入格式

一个 `int` 型的数字,`0 <= num <= 2` 的 31 次方

## 输出格式

也是一个 `int` 型数字,代表字符串的总共可能性

**输入样例**

输入: 12258

**输出样例**

输出: 5

解释: 12258 有 5 种不同的翻译,分别是 "bccfi", "bwfi", "bczi", "mcfi" 和 "mzi"

问题分析:

要解决这个问题,即计算一个数字的不同翻译方法,实际上可以通过动态规划来实现。我们需要将输入数字看作一串字符,然后根据规则将其翻译成相应的字符串。

解决思路

动态规划:

我们定义一个动态规划数组 dp,其中 dp[i] 表示在前 i 个字符的翻译方案数量。

对于一个长度为 n 的字符串,我们考虑以下两种情况:

只将当前字符翻译成对应的字母。

将当前字符和前一个字符结合起来翻译(需要确保这两个字符组成的数字合法,且在 025 之间)。

状态转移方程:

dp[i] = dp[i - 1] 如果当前字符可以单独翻译(即非零)。

dp[i] += dp[i - 2] 如果前两个字符可以合并翻译(即它们组合成的数字在 1025 之间)。

代码如下:

#include <iostream>
#include <string>
using namespace std;

int translateNum(int num) {
    string str = to_string(num); // 将数字转成字符串
    int n = str.length();

    if (n == 0) return 0;
    if (n == 1) return 1; // 单字符的情况

    // 动态规划数组
    int dp[n + 1];
    dp[0] = 1; // 空字符串一种方式
    dp[1] = 1; // 一个字符也有一种方式

    for (int i = 2; i <= n; ++i) {
        // 只翻译当前字符
        dp[i] = dp[i - 1];

        // 结合前一个字符一起翻译
        int twoDigit = stoi(str.substr(i - 2, 2)); // 当前字符及前一个字符形成的数
        if (twoDigit >= 10 && twoDigit <= 25) {
            dp[i] += dp[i - 2]; // 如果能够组合翻译
        }
    }

    return dp[n]; // 返回总的翻译方式
}

int main() {
    // You can add more test cases here
    std::cout << (translateNum(12258) == 5) << std::endl;
    std::cout << (translateNum(1400112) == 6) << std::endl;
    std::cout << (translateNum(2110101) == 10) << std::endl;

    return 0;
}

运行结果:

50 迷人的子序列

# 问题描述

当一个数列,最大值和最小值的差低于某一阈值时,称这个数列是迷人数列。

现给定一个由 `n` 个整数构成的数列和阈值 `k`,问存在多少个连续子序列是迷人的。

## 输入格式

第一行包含 2 个数字 `n, k` (`1 <= n <= 100000`, `0 < k <= 10^9`)

第二行包含 `n` 个整数:`a[1], a[2],..., a[n]` (`0 <= a[i] <= 10^9`)

## 输出格式

输出迷人连续子序列的数目

**输入样例**

4 2
3 1 2 4

**输出样例**

5

**数据范围**

共 10 组数据。2 组数据 `n` 小于 1000;其余数据 `n` 等于 100000。

问题分析:

  1. 定义迷人数列:一个连续的子序列是迷人的,如果这个子序列的最大值和最小值的差小于阈值 k
  2. 窗口的管理:我们可以利用两个指针(leftright)来维护一个有效的窗口,扩展右指针以包含更多的元素,并调整左指针以确保窗口中的最大值和最小值的差小于 k

算法步骤:

初始化:

使用两个指针 leftright,并定义一个 multisetunordered_map 来保持当前窗口内的元素,这样可以在 O(log n) 复杂度内找到最大值和最小值。

扩展窗口:

通过移动右指针 right 来增大窗口,同时添加新元素到容器中。

收缩窗口:

当窗口内的最大值和最小值的差大于等于 k 时,移动左指针 left 以缩小窗口。

计数迷人子序列:

每次右指针增加,当窗口有效时,所有从 leftright 的子序列都满足条件,可以直接计算数量。

代码如下:

#include <iostream>
#include <vector>
#include <set>

using namespace std;

int countCharmingSubarrays(int n, int k, const vector<int>& nums) {
    multiset<int> currentSet;
    int left = 0, count = 0;

    for (int right = 0; right < n; ++right) {
        currentSet.insert(nums[right]); // 将当前元素插入

        // 检查当前窗口是否满足迷人子序列条件
        while (*currentSet.rbegin() - *currentSet.begin() >= k) {
            currentSet.erase(currentSet.find(nums[left])); // 移除左边的元素
            left++; // 收缩窗口
        }

        // 所有从左边到当前右边的子序列都是迷人的
        count += right - left + 1;
    }

    return count;
}

int main() {

    // You can add more test cases here
    std::vector<int> sequence1 = {3, 1, 2, 4};
    std::vector<int> sequence2 = {0, 3, 4, 5, 2, 1, 6, 7, 8, 9};
    std::vector<int> sequence3 = {1, 3, 5, 5, 3, 1};

    std::cout << (countCharmingSubarrays(4, 2, sequence1) == 5) << std::endl;
    std::cout << (countCharmingSubarrays(10, 5, sequence2) == 28) << std::endl;
    std::cout << (countCharmingSubarrays(6, 3, sequence3) == 14) << std::endl;

    return 0;
}

运行结果:

58 五子棋获胜策略

# 问题描述
- 假设存在一个五子棋棋盘,大小未知。上面只摆放了一些白色的棋子,现在你的手中还有一个白色棋子,要求找出在棋盘的哪些位置摆放这个棋子,能够使棋盘上出现五颗棋子连成一线。
- 备注:棋盘上当前不存在连成一条线的五个棋子,但至少存在一个点能够凑出五子一线(不限于横、竖、斜线)

## 输入格式
- 第一行输入一个正整数 `n`,表示棋盘的宽度,棋盘总共可以容纳 `n^2` 个棋子。
- 第 2 到 `n+1` 行输入 `n` 个数字。每次输入 `n` 个数,其中 `1` 代表有棋子,`0` 代表没有棋子。

## 输出格式
- 如果有 `n` 个可放置点,输出 `n` 行。
- 每行输出两个数字,以空格分隔,分别代表放置点在棋盘上的行数和列数。
- 输出顺序需要按照行数从小到大、列数从小到大的顺序。

## 输入样例
```
6  
0 0 0 0 0 0  
0 1 0 0 0 0  
0 0 1 0 0 0  
0 0 0 1 0 0  
0 0 0 0 1 0  
0 0 0 0 0 0  
```


## 输出样例

1 1
6 6


## 数据范围
- 第一行中,棋盘宽度为 `[1, 10)` 中的整数。
- 第 2 到 `n+1` 行中,只会出现 `0` 或 `1`。

问题分析:

这个题目跟我之前做过的一个题目很像,那个是动态的,双方互相落子判断谁胜利,这个是给你一个棋局,没有黑白方,判断落子胜利有几种方式,原理就是落子时,判断上下左右左斜右斜,且在规定范围内,是否可以达到五子连珠。

代码如下:

#include <iostream>
#include <vector>
#include <utility>
#include <sstream>

using namespace std;

// 函数检查某个位置可以形成五子连线
bool canFormLine(int x, int y, const vector<vector<int>>& board, int n) {
    // 定义四个方向:右,下,右下,左下
    int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};

    for (auto& dir : directions) {
        int count = 1; // 当前位置记为1
        int dx = dir[0], dy = dir[1];

        // 检查正向
        for (int step = 1; step < 5; ++step) {
            int nx = x + dx * step;
            int ny = y + dy * step;
            if (nx >= 0 && nx < n && ny >= 0 && ny < n && board[nx][ny] == 1) {
                count++;
            } else {
                break;
            }
        }

        // 检查反向
        for (int step = 1; step < 5; ++step) {
            int nx = x - dx * step;
            int ny = y - dy * step;
            if (nx >= 0 && nx < n && ny >= 0 && ny < n && board[nx][ny] == 1) {
                count++;
            } else {
                break;
            }
        }

        // 如果形成五子连接,则返回 true
        if (count >= 5) return true;
    }

    return false; // 没有符合条件的连线
}

// 主解决方案函数
string solution(int n, vector<vector<int>>& board) {
    vector<pair<int, int>> results;

    // 检查每个位置是否能放置新棋子形成五子连线
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (board[i][j] == 0) { // 只检查空位
                if (canFormLine(i, j, board, n)) {
                    results.emplace_back(i + 1, j + 1); // 记录行列,+1因要求从1开始
                }
            }
        }
    }

    // 格式化输出结果
    stringstream ss;
    ss << "{";
    for (size_t i = 0; i < results.size(); ++i) {
        ss << "{" << results[i].first << ", " << results[i].second << "}";
        if (i < results.size() - 1) {
            ss << ", "; // 不在最后一个元素后添加逗号
        }
    }
    ss << "}"; // 结束括号

    return ss.str(); // 返回结果字符串
}

int main() {
    vector<vector<int>> array = {
        {0, 0, 0, 0, 0, 0},
        {0, 1, 0, 0, 0, 0},
        {0, 0, 1, 0, 0, 0},
        {0, 0, 0, 1, 0, 0},
        {0, 0, 0, 0, 1, 0},
        {0, 0, 0, 0, 0, 0}
    };

    //cout << solution(6, array) << endl;
    cout << (solution(6, array) == "{{1, 1}, {6, 6}}") << endl;

    return 0;
}

运行结果:

困难题目

已完成 2

8 进制求和转换

# 问题描述

给定两个二进制字符串,返回他们的和(用十进制字符串表示)。输入为非空字符串且只包含数字 1 和 0 ,请考虑大数问题。时间复杂度不要超过 O(n^2),其中 n 是二进制的最大长度。

## 输入格式

每个样例只有一行,两个二进制字符串以英文逗号“,”分割

## 输出格式

输出十进制格式的两个二进制的和

**输入样例**:

101,110

**输出样例**:

11

**数据范围**:

每个二进制不超过 100 个字符,JavaScript 语言下请考虑大数的情况。

问题分析:

  1. 函数签名:
    • string addBinary(const string &a, const string &b):这个函数接收两个二进制字符串,并返回它们的十进制和作为字符串。
  1. 变量初始化:
    • string result;:用于存储二进制加法的中间和最终结果(在反转之前)。
    • int carry = 0;:初始化进位为0。
    • int i = a.size() - 1;int j = b.size() - 1;:分别初始化两个字符串的索引,从末尾开始遍历。
  1. 循环逻辑:
    • while (i >= 0 || j >= 0 || carry):当任一字符串还有未处理的位或存在进位时,继续循环。
    • 在循环内部,首先处理进位,然后根据索引 ij 的有效性,将对应位置的字符转换为数字并加到 sum 上。
    • 更新进位 carry 和结果字符串 result
  1. 结果处理:
    • reverse(result.begin(), result.end());:由于是从字符串末尾开始构建结果,因此最后需要反转字符串。
    • long long decimalSum = stoll(result, 0, 2);:将二进制字符串转换为十进制长整数。这一步实际上是多余的,因为题目要求返回的是十进制字符串,而不是长整数。
    • return to_string(decimalSum);:将十进制长整数转换回字符串并返回。由于前面的 stoll 转换是多余的,这一步也可以优化为直接返回 result 字符串(在反转之后)。

代码如下:

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

// 函数用于二进制字符串的加法
string addBinary(const string &a, const string &b) {
    string result;
    int carry = 0;  // 进位
    int i = a.size() - 1;
    int j = b.size() - 1;

    while (i >= 0 || j >= 0 || carry) {
        int sum = carry; // 先将进位加上
        if (i >= 0) {
            sum += a[i] - '0'; // 将字符转换为数字
            i--;
        }
        if (j >= 0) {
            sum += b[j] - '0'; // 将字符转换为数字
            j--;
        }
        carry = sum / 2; // 计算新的进位
        result.push_back((sum % 2) + '0'); // 结果取余,转换为字符
    }

    reverse(result.begin(), result.end()); // 反转结果
    long long decimalSum = stoll(result, 0, 2);
    return to_string(decimalSum);
}

// 主函数


int main() {
    // You can add more test cases here
    std::cout << (addBinary("101", "110") == "11") << std::endl;
    std::cout << (addBinary("111111", "10100") == "83") << std::endl;
    std::cout << (addBinary("111010101001001011", "100010101001") == "242420") << std::endl;
    std::cout << (addBinary("111010101001011", "10010101001") == "31220") << std::endl;

    return 0;
}

运行结果:

27 查找热点数据

# 问题描述

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。

- 1 <= nums.length <= 10^5
- k 的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

你所设计算法的时间复杂度必须优于 O(n log n) ,其中 n 是数组大小。

**示例 1**

输入: nums = [1,1,1,2,2,3], k = 2

输出: [1,2]

**示例 2**

输入: nums = [1], k = 1

输出: [1]

问题分析:

  1. 参数:
    • vector<int>& nums: 输入的整数数组。
    • int k: 需要返回的前k个高频元素的数量。
  1. 局部变量:
    • unordered_map<int, int> freqMap: 用于存储每个数字的频率。
    • vector<pair<int,int>> result: 存储哈希表中的键值对(数字及其频率)。
    • stringstream ss: 用于构建最终返回的字符串。
  1. 逻辑流程:
    • 构建频率映射: 遍历输入数组 nums,使用 unordered_map 记录每个数字的频率。
    • 存储映射到结果向量: 将 freqMap 中的每个键值对(数字及其频率)添加到 result 向量中。
    • 排序: 使用 sort 函数对 result 向量进行排序,排序依据是元素的频率(降序)。
    • 构建返回字符串: 遍历排序后的 result 向量的前 k 个元素,将它们转换为字符串并使用逗号分隔,存储在 stringstream 中。
    • 返回结果: 将 stringstream 中的内容转换为字符串并返回。

代码如下:

#include <iostream>  
#include <vector>  
#include <unordered_map>  
#include <queue>  
#include <sstream>  
#include <algorithm>  
  
using namespace std;  
   
string topKFrequent(vector<int>& nums, int k) {  
    // 使用哈希表记录每个元素的频率  
    unordered_map<int, int> freqMap;  
    for (int num : nums) {  
        freqMap[num]++;  
    }  
    vector<pair<int,int>> result;
    for(auto x : freqMap){
        result.push_back(x);
    }

    sort(result.begin(), result.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
        return a.second > b.second;
    });

    stringstream ss;
     for (size_t i = 0; i < k; ++i) {  
        ss << result[i].first;  
        if (i < k - 1) {  
            ss << ",";  
        }  
    }

    return ss.str();
}   

int main() {
    //  You can add more test cases here
    std::vector<int> nums1 = {1, 1, 1, 2, 2, 3};
    std::vector<int> nums2 = {1};
    //cout << topKFrequent(nums1, 2) << endl;
    std::cout << (topKFrequent(nums1, 2) == "1,2") << std::endl;
    std::cout << (topKFrequent(nums2, 1) == "1") << std::endl;

    return 0;
}

运行结果:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

马武寨山的猴子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值