牛客网-编程题练习(字符串数组相关)

本文探讨了多种经典算法问题的解决方法,包括查找字符串中首次出现且唯一出现的字符、在特定排序的二维数组中查找指定整数、寻找链表中倒数第k个节点及提取最长数字字符串。通过具体实例解析,展示了不同场景下的算法实现。

day 01

第一题:

题目:在字符串中查找第一次出现且只出现一次的字符。
如输入“asdfgfdsa”,则输出‘g’。

算法解析:

算法1:
从头到尾开始扫描这个字符串。当访问到某个字符时,一次和后面的字符比较。如果后面字符没有与该字符相同的字符,就说明这个字符是第一次出现的字符。如果字符串有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路时间复杂度是O(n^2)。

解法二,

既然题目与字符串中字符的次数有关,我们可以来统计一下字符出现的次数。那么怎么统计这个次数呢

我们需要一种容器,这种容器可以存放字符出现的次数。并且次数和还存在着一种映射关系。

能够满足这种需求的容器就是哈希表了。我们可以将字符的ASCII码值作为哈希表的下标,即key值。字符出现的次数,作为哈希表对应下标内容。即value值。

这里写图片描述

#include<stdio.h>
char firstNotRepeating(char* pString)
{
    if(pString==NULL)
    {
        return '\0';
    }
    int TableSize=258;
    int  HashTable[TableSize];
    //初始化哈希表
    int i=0;
    for(;i<TableSize;i++)
    {
        HashTable[i]=0;

    }
    //根据字符acsii码值
    //确定哈希表的key值和哈希表的value值

    char *HashKey=pString;
    while(*HashKey!='\0')
    {
        //(*HashKey)++是key值变化
        //HashTable[HashKey]++是value值加1
        //如果遇到相同的字符,value加1
        HashTable[*(HashKey++)]++;

    }


    HashKey=pString;

    while(*HashKey!='\0')
    {
        //HashTable[*HashKey]==1
        //则说明找到了只出现一次的字符

        if(HashTable[*HashKey]==1)
        {
            return *HashKey;
        }
        HashKey++;

    }
    return '\0';

}
int main()
{
        //测试字符串中只出现一次的字符
    char str1[]="hheello";
    char ret_1=firstNotRepeating(str1);
    //测试字符串中不存在只出现一次的字符
    char str2[]="world world";
    char ret_2=firstNotRepeating(str2);
    //测试所有字符串只出现一次
    char str3[]="owmuch";
    char ret_3=firstNotRepeating(str3);
    //测试空串
    char str4[]="        ";
    char ret_4=firstNotRepeating(str3);
    printf("expected o,actual :%c\n",ret_1);
    printf("expected  ,actual :%c\n",ret_2);
    printf("expected o,actual :%c\n",ret_3);
    printf("expected  ,actual :%c\n",ret_4);

    return 0;

}

运行结果:

expected o,actual :o
expected  ,actual : 
expected o,actual :o
expected  ,actual :o

第2题:

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解题思路:

解法1.以行为单位。依次遍历数组的每个元素,这种算法的时间复杂度为为N^2
解法2,根据数组的特性,从左到右,一次增大,从下到上,一次减小。可以将我们的搜索出发点设为左下角的坐标,这样如果查找的元素比左下角的元素大,则了列数+1,如果比左下角的元素小,就把行数-1。如果相同,则说明找到了。其他元素同理。

这里写图片描述

1.求出行数,列数
2,设置出发点为左下角的点
3.开始循环查找
( 1)如果目标元素比数组元素小,则将行数减1
( 2)如果目标元素比数组元素大,则将列数加1
( 3)如果目标元素与数组相等,则返回true;

class Solution
{
    public:
    bool Find(int target,vector<vector<int>> array)
    {
        int row=array.size();
        int col=array[0].size();
        int i=0,j=0;
        for(i=row-1,j=0;i>=0&&j<col;)
        {
            if(target==array[i][j])
            {
                return true;
            }
            else if(target<array[i][j])
            {
                i--;
                continue;
            }
            else
            {
                j++;
                continue;
            }

        }
        return false;
    }
};

第3题

输入一个链表,输出该链表中倒数第k个结点。

1.定义两个指针:快指针,
2.慢指针。让快指针从头指针开始遍历先走K-1步,此时,慢指针保持不变。
3.从第k步开始,慢指针也开始从链表的头指针开始遍历。由于连个指针距离保持在K-1步,当快指针到达链表的节点时,慢指针刚好走到第K个节点

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead == NULL || k == 0)    //判断指针是否为空且k是否为0
            return NULL;
        ListNode* p1 = pListHead;//定义一个快指针从头开始先走k-1步
        ListNode* p2 = pListHead;//定义一个慢指针从开始走
        int n = k - 1;
        while(n--)
        {
            if(p2->next != NULL)
                p2 = p2->next;
            else                //如果链表节点个数小于k,直接返回
                return NULL;
        }

         while(p2->next != NULL)
            {
                p2 = p2->next;
                p1 = p1->next;
        }

        return p1;

    }
};

求一个字符串中的最大长度的数字字符串,并将该字符串的长度返回

解析:
要求取出最长数字字符串,说明字符串中可能存在多个数字字符串,因此我们要设置一个变量(tmpCount)来保存最大字符串的长度,还需要定义一个变量来保存临时字符串等的长度(maxCount)。并设置一个iNode记录数字字符串的位置。

当遇到数字时,tmpCount开始计数,如果此时tmpCount大于maxCount,则更新maxCount和INode.否则保持不变。

如果不是数字,tmpCount置为0即可。

遍历完成,如果maxCount没有更新,则直接返回空串
否则开始拷贝最大长度的数字字符串。
这里写图片描述

#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 128
int CountStr(char **OputStr,const char *InputStr)
{

    if(InputStr==NULL||InputStr=='\0')
    {
        *OputStr=" ";
        exit(1);
    }
    int tmpCount=0;
    int maxCount=0;
    int tmpPos=0;
    int length=strlen(InputStr);
    //开始循环遍历字符串
    int i=0;
    for(i=0;i<length;i++)
    {
        if(InputStr[i]>='0' && InputStr[i]<='9')
        {
            tmpCount++;
            if(tmpCount>=maxCount)
            {
                maxCount=tmpCount;
                tmpPos=i;
            }

        }
        else
        {
            tmpCount=0;
        }
    }
    if(maxCount==0)
    {
        *OputStr=" ";
        return 0;
    }
    //开始拷贝目标字符串
    *OputStr=(char *)malloc(sizeof(char)*(maxCount+1));
    strncpy(*OputStr,InputStr+tmpPos-maxCount+1,maxCount);

    (*OputStr)[maxCount]='\0';//此处*OputStr必须加括号,否则会产生段错误
    return maxCount;
}
int main()
{

    char b[100],c[100];
    int num=0;
    char *a=c;
    scanf("%s",b);
    num=CountStr(&a,b);
    printf("数字字符串:%s\n",a);
    printf("num=%d\n",num);

    return 0;
}

运行结果:

[zyc@localhost string]$ ./a.out 
asdf123
数字字符串:123
num=3
[zyc@localhost string]$ ./a.out 
a1s2d3
数字字符串:3
num=1
[zyc@localhost string]$ ./a.out 
asdfg
数字字符串: 
num=0
[zyc@localhost string]$ ./a.out 
123456
数字字符串:123456
num=6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值