Day3 字符串中找出连续最长的数字串、数组中出现次数超过一半的数字

简介: Day3 字符串中找出连续最长的数字串、数组中出现次数超过一半的数字

选择题

1.进程管理

题目:32位系统中,定义 **a[3][4] ,则变量占用内存空间为()

选项:

  • A、4
  • B、48
  • C、192
  • D、12

分析:本题考的是 指针 大小及数组大小的计算,在 32 位平台下,指针大小为 4byte,而在 64 位平台下,指针大小为 8byte;在计算二维数组的大小时,需要通过 行 * 列 * 类型大小 的方式进行计算

在本题中,a 为一个 二维二级指针数组,无论是几级指针,在 32 位平台中都为 4byte,因此 a 的实际占用空间为 3 * 4 * 4 = 48

注意:数组名表示数组中首元素的地址,但存在两种特殊情况:

  • sizeof(数组名) 计算的是整个数组的大小
  • &数组名 取出的是整个数组的地址

结果:B

2.计算机组成原理

题目:假设在一个 32 位 little endian(小端序) 的机器上运行下面的程序,结果是多少?

#include <stdio.h>
int main() {
  long long a = 1, b = 2, c = 3;
  printf("%d %d %d\n", a, b, c);
  return 0;
}


选项:

  • A、1,2,3
  • B、1、0、2
  • C、1、3、2
  • D、3、2、1

分析:小端序 机器中,低位存储数据的低地址,大端序 则相反;long long 占用 8byte 大小的空间,%d 匹配 int,占用 4byte 空间,当强行使用 %d 匹配 long long 输出数据时,会发生截断行为,导致数据读取时出现错位

关于 大小端序的相关问题可以查看这篇文章:《C语言进阶——数据在内存中的存储

结合 printf 打印时的栈帧,可以得到下图中的分析

注意:在栈中,先入栈的最后出,因此是 c 先入栈、最后出栈;高精度数据向低精度数据进行转换时,会发生 截断 行为,导致数据丢失,因此要注意数据与格式匹配(long long 匹配格式为 lld

结果:B


编程题

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

题目链接:OR59 字符串中找出连续最长的数字串

题目分析:存在一个字符串 str,其中包含数字和其他字符,要求计算出 最长的数字子串;题目比较简单,直接 遍历+判断+统计,不断更新 最长数字子串的值,即可得到答案

遇见数字时,记录当前位置 begin,不断向后走,直到遇见非数字或结尾,记录当前位置为 end,构造字符串并与历史记录的最长数字子串进行比较,如果比其长,则更新 numStr

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str;
    while (getline(cin, str))
    {
        string numStr;  //最长数字子串
        auto it = str.begin();
        while (it < str.end())
        {
            if (isdigit(*it))
            {
                //通过区间构造数字子串
                auto begin = it;
                while (it != str.end() && isdigit(*it))
                    ++it;
                auto end = it;
                string tmp(begin, end);
                //更新最长的数字子串
                if (tmp.size() > numStr.size())
                    numStr = tmp;
            }
            else
                ++it;
        }
        cout << numStr << endl;
    }
}


注意:在进行 while 循环时,需要特别注意边界问题,避免出现越界

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

题目链接:JZ39 数组中出现次数超过一半的数

题目分析:非常经典的题目,存在一个数组,其中某个数值超过了数组长度的一半,要求找出这个数,既然某个数超过了数组长度的一半,那么我们可以将其中的每个数出现次数统计起来,再次遍历即可确定这个数,当然这种解法比较废空间,除此之外,我们还可以将数组进行排序,中位数即出现次数超过一半的值

解法一:通过容器将其中的值与出现次数进行统计

这里使用 map 对数据进行存储,然后对 map 进行遍历确认数值即可

时间复杂度:N + logN + N / 2

空间复杂度:N / 2

#include <map>
class Solution 
{
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        map<int, int> table;    //建立 kv 表
        for(auto e : numbers)
            table[e]++;
        int n = numbers.size() / 2; //数组长度
        for(auto e : table)
        {
            //这个数值必然存在
            if(e.second > n)
                return e.first;
        }
        return 0;
    }
};


这种解法时间和空间效率都比较低,优点就是比较容易想到

解法二:将数组进行排序,然后返回中位数

排序后,出现次数超过一半的值,必然位于中间

时间复杂度:N * logN

空间复杂度:logN

class Solution 
{
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        //先将数据进行排序
        sort(numbers.begin(), numbers.end());
        //直接返回中位数值
        return numbers[numbers.size() / 2];
    }
};


这个代码就更简单了,直接两行解决问题,不过还是不符合进阶要求

解法三:将数组中,不相同的两个值置为 -1,最后再遍历数组,不为 -1 的值,就是目标

因为某个值出现次数超过一半,所以每 “去除” 两个不同的值,必然会将 某个值 以外的全部值去除,剩下的自然就是目标值了

时间复杂度:N + N —> N

空间复杂度:1

class Solution
{
public:
    int MoreThanHalfNum_Solution(vector<int> numbers)
    {
        size_t i = 0;
        size_t j = 0;
        while (i < numbers.size() && j < numbers.size())
        {
            // j 找到与 i 不同的值
            while (j < numbers.size() && numbers[i] == numbers[j])
                j++;
            //如果两个都没有越界,则置 -1
            if(i < numbers.size() && j < numbers.size())
                numbers[i] = numbers[j] = -1;
            //将 -1 跳过(-1 不参与比较)
            while (i + 1 < numbers.size() && numbers[i + 1] == -1)
                i++;
            while (j + 1 < numbers.size() && numbers[j + 1] == -1)
                j++;
            i++;
            j++;
        }
        //再次遍历,不为 -1 的值就是目标值
        for (auto e : numbers)
        {
            if (e != -1)
                return e;
        }
        return 0;
    }
};


这种解法是最优解,即减少了时间,也兼顾了空间

注意:在进行 while 循环时,需要特别注意越界问题,同时在涉及解引用时,也要注意越界问题

今天的选择题都和数据在内存中的存储有关;编程题则比较简单,无非就是进行遍历判断比较,编码时需要注意越界问题



相关文章推荐


Day2 排序子序列、倒置字符串


Day1 组队竞赛、删除公共字符


C++题解 | 逆波兰表达式相关


C语言题解 | 去重数组&&合并数组


C语言题解 | 消失的数字&轮转数组
目录
相关文章
|
2月前
|
算法 前端开发
3035. 回文字符串的最大数量
3035. 回文字符串的最大数量
35 0
|
2月前
leetcode-1438:绝对差不超过限制的最长连续子数组
leetcode-1438:绝对差不超过限制的最长连续子数组
28 0
【剑指offer】-数组汇总出现次数超过一半的数字-27/67
【剑指offer】-数组汇总出现次数超过一半的数字-27/67
|
10月前
|
C++
LeetCode 43. 字符串相乘C++代码 超过100%
LeetCode 43. 字符串相乘C++代码 超过100%
58 0
剑指offer 40. 数组中出现次数超过一半的数字
剑指offer 40. 数组中出现次数超过一半的数字
57 0
|
人工智能
最长连续不重复子串
最长连续不重复子串
110 0
最长连续不重复子串
|
C++
13.数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
47 0
|
算法 前端开发 测试技术
【前端算法】字符串中连续最多的字符以及次数
双指针与双层循环“跳步”的比较
|
算法
剑指offer之数组出现次数超过一半的数字
剑指offer之数组出现次数超过一半的数字
104 0