DAY-2 | 哈希表、指针与区间划分:字符种数统计问题

发布于:2023-01-07 ⋅ 阅读:(303) ⋅ 点赞:(0)

这里是C语言刷题日志,整理了博主本人平时做练习遇到的问题以及相关的总结。不定时对文章内容更新优化,持续维护。


目录

一、题干

二、题解

1. 查表法(标记、哈希表)

2. 指针与区间划分(回头法)

三、方法总结


一、题干

牛客网链接

HJ10 字符种数统计https://www.nowcoder.com/practice/eb94f6a5b2ba49c6ac72d40b5ce95f50


二、题解

1. 查表法(标记、哈希表)

题干规定了出现的字符均是 ascii 值小于127的字符,因而我们可以定义一个“标记数组”用于标记出现过的字符。

这就好像上课时老师点名用的花名册,名册原本就记录了一共127位学生的名字。点名时,哪位学生到了,就在他的名字后打个“√”。本题的思想也类似于此。

根据题干,我们将标记数组的大小定义127 ,然后将字符直接作为数组的下标,在数组中进行标记。注意:可打印的字符类型本身就能转换为数值(ASCII),这一点非常巧妙。若数组中该位置没有被标记过,则表示第一次出现,从而进行计数;否则表示重复字符,不进行计数。

示例
用查表法, "aca" ,首先把 a 字符 ( ascii 值为 97 ) 作为下标,将“标记数组”的第 97 位置为 1 ,下次如果还有 a 字符出现,到下标 'a' 或者 97 的位置一看是 1, 就表示 a 已经统计过了。
#include <stdio.h> 

int main() { 
    char tmp[501] = {0};     //该数组用于输入字符串
    while(~scanf("%s", tmp)) {     //用于多组输入
        char table[128] = {0};    //定义标记数组
        char* ptr = tmp;     //指针指向我们输入的字符串,用于字符串的遍历
        int count = 0; 

        while(*ptr != '\0') { 
            if (table[*ptr] != 1) {    //判断字符ascii值作为下标的位置是否被标记过,是否是重复字符 
                count++; //当前字符的位置没有被标记过,表示没有出现过,则计数+1 
            }
            table[*ptr++] = 1;    //将字符ascii值作为下标的位置进行标记,置为1 
        }

        printf("%d\n", count); 
    }
    
    return 0; 
}

2. 指针与区间划分(回头法)

这个方法的核心思路在于“回头查重”,每遍历到字符串中的一个字符,就回头对它前面的所有字符进行检查,看它之前是否出现过。如果出现过,说明有重复,则不计数;否则则进行计数。

我们用查重函数duplicateCheck来完成“判断是否有重复”这个任务,它的返回值是“是”或“否”,我们将函数的返回值定义为int类型。它的具体功能是:

  1. 传入在main函数中遍历到的字符*p(即ch),*p在字符串中的位置(用指针p表示),字符串本身的首元素地址arr
  2. 查重的范围是:字符串第一个字符 到 该字符本身 之间。我们用当前位置p减去首字符的位置arr来表示这个查重范围。
#include<stdio.h>

int duplicateCheck(char* arr, char* p, char ch) {
    int size = p - arr;    //查重范围框定,从首元素到当前元素之间
    for (int i = 0; i < size; i++) {
        if (ch == arr[i]) {
            return 1;
        }
    }
    return 0;
}

int main() {
    unsigned char arr[500];
    scanf("%s", arr);    //没有用多组输入
    int count = 0;
    char* p = arr;

    while (*p != '\0') {
        p++;    //注意p++的位置,必须放在这里,不能放在while循环的最后,否则会因为continue的存在而死循环

        if (duplicateCheck(arr, p, *p)) {
            continue;
        }
        else {
            count++;
        }
    }
    printf("%d", count);
    return 0;
}

三、方法总结

1. 哈希表查找是一个很巧妙的方法,在去重、找重等题型中很常见也很适用。可以在牛客网【华为机试】组题中刷刷相关的题。

2. 在第二种方法中提到,while循环内部出现continue时,最好多留个心眼,检查一下它会不会出现死循环。在while与continue之间,应当有能改变循环变量的语句。

3. 需要多回顾。


网站公告

今日签到

点亮在社区的每一天
去签到