【每日训练】字符串中找出连续最长的数字串&&数组中出现次数超过一半的数字

目录

1.字符串中找出连续最长的数字串

题目链接:

 解析:

程序:

2.数组中出现次数超过一半的数字

题目链接:

测试用例:

解析:

程序:


1.字符串中找出连续最长的数字串

题目链接:

字符串中找出连续最长的数字串_牛客题霸_牛客网 (nowcoder.com)

 解析:

题目描述

        输入一行字符串,输出此字符串中的最长数字串。

思路

        在遍历一遍字符串的基础上进行统计,可以利用当前字符是否是数字字符(ASCII)进行判断此时是数字串还是其余串。

        此时可以创建一个string变量,来保存每次的数字串。那么如何保存最大长度的那个数字串呢?可以在创建一个string空间, 用来保存最终的数字串。每次数字串结束(当前字符不为数字字符)时,目前保存的数字串和最终的数字串进行比较大小,大就将最终数字串更新,小就不做更新即可。

        比如使用示例:

         当然不用两个字符串来保存最终字符串也可以,对于一个进行动态规划控制也可。(利用.substr)

程序:

        注意最后一个数字串的问题,因为如果不对最后一个字符处理的话,遍历结束,最后一个数字串和最终串就比不了。

        这里可以采用<=str.size()的方法。我们知道string size()方法存储的是有效字符的个数,在字符串中最后一个必然保存的是'\0'。而\0的ASCII码和数字字符不一样,所以最后一次必然进入最终串的比较中。

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

int main()
{
    string str, cur, ptr;  // 输入字符串 存放数字串 最终数字串
    cin >> str;
    
    for (int i = 0; i <= str.size(); i++)  // 判断条件不加= 则如果最后一个数字串位于末尾就统计不上
    {
        if (str[i] <= '9' && str[i] >= '0')  // 数字字符
        {
            cur += str[i];  // 从空开始尾插字符
        }
        else  // 不是数字字符:1.判断cur和ptr的长度 2.清空cur
        {
            if (cur.size() > ptr.size()) ptr = cur;
            cur.clear();  // 清空,下一次是新的数字串
        }
    }
    cout << ptr << endl;  // 输出结果
    return 0;
}

2.数组中出现次数超过一半的数字

题目链接:

数组中出现次数超过一半的数字_牛客题霸_牛客网 (nowcoder.com)

测试用例:

 

解析:

题目描述

        在一个数组中找到出现次数超过一半的那个数。(题目说明:保证输入非空,保证有解

思路

        针对此题,我有三种思路:1.直接计数2.排序找3.众数抵消法

        1.直接计数:读题,我们可以发现数据元素的值不超过10000,那么我们能否模拟一个key-value模型,key记录当前数作为一个数组的下标,value记录出现次数。比如:

        然后在遍历一遍判断哪个大找到对应key值输出即可。注意value值必须大于数组长度的一半,比如上述例子就不存在,如果不存在次数,即可以对照value值验证即可。

        2.排序找:排序的话会把数组元素从小到大排序一遍,如果里面存在出现次数大于数组一半的次数,那么中间位置一定是这个数,当然如果不存在的话就要遍历去比对次数是否正确。

 

         3.众数抵消法:定义一个众数为出现次数大于数组长度一半。其余为非众数。我们可以在遍历数组的时候定义一个res表示当前待众数(待定)和times记录此时和非众数的抵消之后的数。

        首先大局观的想一下,如果存在此众数,那么一定是一半以上,其余的都是非众数。非众数个数和众数个数相互抵消,那么留下来的只有众数。(注意前提是存在众数)

        进行遍历时,和此时存储的res相比,如果相等就增加次数,不相等判断res数的次数是否为0,为0则此数就不是众数了,换成当前比较数,并且times设置为1.如果res数次数不为0就进行--抵消。

        需要注意在上述的三种方法中最后出的结果一定正确,因为题目保证有解。如果不保证有解的情况下就要进行遍历判断此数究竟是不是大于数组的长度。

程序:

直接计数

class Solution {

public:

    int MoreThanHalfNum_Solution(vector<int> numbers) {

        int arr[10001] = {0};

        for (int i = 0; i < numbers.size(); i++)   // 遍历一遍统计个数

            arr[numbers[i]]++;

        int maxi = 0;  // 在遍历一遍数组 找最大

        for (int i = 1; i < 10001; i++)

            maxi = arr[maxi] > arr[i] ? maxi : i;

        return maxi;   //保证有解

    }

};

 排序找:

class Solution {

public:

    int MoreThanHalfNum_Solution(vector<int> numbers) {

        // 首先进行排序,因为如果某个数字出现次数超过了数组长度的一半,一定位于中间位置。

        // 此题因为保证有解,所以中间的数不需要判断就是,但是如果存在没有解的情况下是要进行判断的

        sort(numbers.begin(), numbers.end());

        int num = numbers[numbers.size() / 2], j = 0;

        // 当前题不需要进行验证,但是此处我验证一下

        for (int i = 0; i < numbers.size(); ++i)

        {

            if (numbers[i] == num) j++;

        }

        if (j > numbers.size() / 2) return num;

        return -1;  // 错误返回

    }

};

 众数抵消法:

class Solution {

public:

    int MoreThanHalfNum_Solution(vector<int> numbers) {

        // 众数与非众数思路

        // 这里众数指出现次数超过一半

        int res = numbers[0];  // 第一个数开始

        int times = 1;  // 记录个数



        for (int i = 1; i < numbers.size(); ++i)

        {

            if (numbers[i] != res)

            {

                if (times == 0)  // 此时此数出现次数抵消完毕,换下一个数

                {

                    res = numbers[i];

                    times = 1;

                }

                else{

                    times--;

                }

            }

            else{

                times++;  // 相同数相加

            }

        }

        // 因为此题说明,可以不用验证,但是正常情况下如果没有众数的话是要进行验证的:

        times = 0;  // 用此变量去计数

        for (int i = 0; i < numbers.size(); ++i)

        {

            if (res == numbers[i]) times++;

        }

        if (times > numbers.size() / 2) return res;

        return -1;  // 不存在此数

    }

};

        上述代码仅供参考~大家加油!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值