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

简介: ```markdown## 题干[牛客网链接](https://www.nowcoder.com/practice/eb94f6a5b2ba49c6ac72d40b5ce95f50)## 题解1. **查表法(哈希表)**:利用数组标记出现过的 ASCII 值小于127的字符,首次出现计数,重复则忽略。2. **指针与区间划分(回头法)**:遍历字符串,对每个字符检查其前所有字符是否重复,重复则不计数。## 方法总结- 哈希表在去重问题中非常实用,可多做相关练习。- 使用`continue`时注意避免死循环,确保循环变量会改变。- 多回顾此类问题以巩固理解。```

一、题干


牛客网链接


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类型。它的具体功能是:


传入在main函数中遍历到的字符*p(即ch),*p在字符串中的位置(用指针p表示),字符串本身的首元素地址arr

查重的范围是:字符串第一个字符 到 该字符本身 之间。我们用当前位置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. 需要多回顾。


相关文章
|
6月前
|
存储 编译器 C语言
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
126 0
|
6月前
|
存储 C语言
字符指针变量与字符数组的比较
字符指针变量与字符数组的比较
46 3
|
6月前
|
存储 C语言
字符指针作为函数参数
字符指针作为函数参数
59 2
|
6月前
|
存储 C语言
C语言中的字符指针技术详解
C语言中的字符指针技术详解
52 0
|
6月前
|
算法
"刷题记录:哈希表+双指针 | leetcode-2465. 不同的平均值数目 "
该文段是一篇关于编程题目的解答,主要讨论如何找到数组中所有不同平均值的个数。作者首先使用排序和哈希集来解决,将数组转为列表排序后,通过双指针计算平均值并存入哈希集以去重。然后,作者发现可以优化方案,通过双指针在排序后的数组中直接计算两数之和,用哈希集记录不重复的和,从而避免实际计算平均值,提高了算法效率。最终代码展示了这两种方法。
55 0
|
6月前
|
存储 机器学习/深度学习 人工智能
【算法基础】基础算法(三)--(双指针算法、位运算、离散化、区间合并)
【算法基础】基础算法(三)--(双指针算法、位运算、离散化、区间合并)
|
6月前
|
存储 人工智能
字符指针变量和字符数组注意事项(区别)
字符指针变量和字符数组注意事项(区别)
38 0
|
6月前
|
安全 C语言 C++
字符指针做函数参数
字符指针做函数参数
36 1
|
6月前
|
存储 程序员 C++
使用字符指针变量和字符数组的比较
使用字符指针变量和字符数组的比较
68 1
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
22 0