UVa 202 Repeating Decimals(模拟+哈希)

本文解析了UVA-202题目,介绍了如何通过模拟除法找出循环小数及其循环节长度的方法。使用数组记录商和余数出现的位置,通过查找重复余数来确定循环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题地址

https://vjudge.net/problem/UVA-202

给出两个数n,m,0<=n,m<=3000,输出n/m的循环小数表示以及循环节长度。

解题思路

本题是《算法竞赛入门经典》的习题3-7,思路容易想到,实现起来有些细节和边界需要考虑。

不难想到,小数点后循环节的产生是因为计算时的某个余数重复出现,这之后的计算会重复上一次这个余数出现时直到当前位置的结果。因此关键在于找到这个重复出现的余数和它第一次出现的位置。

  • 用res数组存放商的计算结果,dup[i]表示以余数i为计算来源的循环节的开始位置,即该余数i出现时的下一个要得到商的位置,初始化为0。
  • while循环中模拟小学时候的除法,更新当前cnt位置的商的同时,判断计算结果的余数在之前是否出现过(dup[num]是否不为0)。
  • 当出现了循环节的时候,跳出循环,并以dup[num]~cnt-1间的数为所求循环节
  • 需要注意的是余数为0和分子本身为0的情况,他们的循环节都为1!!
  • 由于鸽笼原理, while循环一定会在分母值的次数内结束,其中必定会出现某个余数。
    ps:测试用例要好好研究,非常有利于修正边缘情况的代码。最好每个都手动模拟一下,尤其联系dup[i]的意义观察下标的变化。

AC代码

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

int main()
{
    int num, deno; //num分子,deno分母
    int res[3005], dup[3005]; //res存放计算结果,dup[i]表示余数i出现位置的下一个
    while (cin >> num >> deno)
    {
        int ori_num = num; //记录原始num
        memset(res, 0, sizeof(res));
        memset(dup, 0, sizeof(dup)); //清零
        int cnt = 0; //当前需要产生商的位置
        res[cnt++] = num/deno; //小数点前
        num %= deno;
        while (dup[num] == 0 && num) //如果该余数曾经出现过,或者已经运算出0(循环一定在deno次内结束)
        {
            dup[num] = cnt; //该余数num即将产生第cnt个位置的商
            res[cnt++] = num*10/deno; //产生商
            num = num*10%deno; //更新余数
        }
        printf("%d/%d = %d.", ori_num, deno, res[0]);
        for (int i = 1; i < cnt && i <= 50; ++i) //
        {
            if (i == dup[num]) printf("("); //循环节开始出现的标志
            printf("%d", res[i]);
        }
        if (num == 0) //在第cnt-1位产生0
            printf("(0");
        if (cnt > 50) printf("..."); //超过50位输出...
        printf(")\n"); //闭合循环节
        printf("   %d = number of digits in repeating cycle\n\n", num?cnt-dup[num] : 1);
        //注意num=0(计算得到或分子就是0)时循环节为1
    }
    return 0;
}
<think>好的,用户想找关于哈希表的经典例题或练习题。我先回顾一下哈希表的基本概念和应用场景,确保自己理解正确。哈希表通过键值对存储数据,利用哈希函数快速定位,适合频繁查找的场景。 根据用户提供的引用内容,特别是引用3中提到了几个经典例题,比如最长回文串、词语模式、字母异位词分组等。这些题目都是哈希表的典型应用,需要将这些例子整理出来,并补充其他常见题目。 还要注意用户提到的哈希表优缺点,比如引用2中提到的扩容问题,可能会影响某些题目的解法。此外,引用5中的冲突解决方法,如线性探测和二次探测,可能在题目中有所涉及,比如处理哈希冲突时的策略。 需要确保每个例题都有清晰的描述和解题思路,并指出哈希表在其中的作用。例如,无重复字符的最长子串可以用滑动窗口结合哈希表记录字符位置,这样能快速判断重复字符的位置。 可能用户是准备面试或考试,需要练习这些题目来巩固知识。因此,除了列出题目,还要给出解题的关键点,帮助用户理解如何应用哈希表解决问题。同时,注意引用对应的引用来源,如引用3中的例题需要正确标注。 最后,检查是否有遗漏的经典题目,比如两数之和、存在重复元素等,这些也是常见的哈希表练习题。确保覆盖不同难度级别,从easy到hard,满足用户的不同需求。</think>以下是哈希表的经典例题及练习题汇总,结合其应用场景和解题思路分析: ### 一、基础应用类例题 1. **两数之和(Two Sum)** - 题目:给定数组和整数目标,找出和为目标值的两个元素下标 - 解法:用哈希表存储`值->索引`映射,遍历时查询`target - num`是否存在,时间复杂度$O(n)$[^3] 2. **存在重复元素(Contains Duplicate)** - 题目:判断数组中是否存在重复元素 - 解法:用哈希集合存储已遍历元素,发现重复立即返回`true`,时间复杂度$O(n)$ 3. **最长回文串(Longest Palindrome)** - 题目:用给定字符构造最长回文串 - 解法:统计字符频率,偶数字符全用,奇数字符取最大偶数,时间复杂度$O(n)$ ### 二、模式匹配类例题 4. **词语模式(Word Pattern)** - 题目:判断字符串与单词序列是否遵循相同模式 - 解法:建立双向哈希映射`pattern字符 <-> 单词`,检测双向一致性,时间复杂度$O(n)$ 5. **字母异位词分组(Group Anagrams)** - 题目:将字母异位词组合在一起 - 解法:使用排序后的字符串作为哈希表键,时间复杂度$O(nk \log k)$(k为最长字符串长度) ### 三、滑动窗口结合类 6. **无重复字符的最长子串(Longest Substring Without Repeating Characters)** - 题目:找不含重复字符的最长连续子串 - 解法:滑动窗口+哈希表记录字符最后出现位置,时间复杂度$O(n)$[^3] 7. **最小窗口子串(Minimum Window Substring)** - 题目:在源字符串中找包含目标所有字符的最小窗口 - 解法:滑动窗口+哈希表(需求表/窗口表),时间复杂度$O(|S|+|T|)$ ### 四、特殊场景应用 8. **无重复的DNA序列(Repeated DNA Sequences)** - 题目:找出所有重复出现的长度为10的DNA序列 - 解法:哈希表存储子串出现次数,空间复杂度优化可用滚动哈希,时间复杂度$O(n)$ 9. **LRU缓存机制(LRU Cache)** - 题目:实现LRU缓存淘汰算法 - 解法:哈希+双向链表,保证$O(1)$时间访问和插入[^3] ### 五、进阶练习题 10. **直线上最多点数(Max Points on a Line)** - 解法:用哈希表存储斜率计数,注意处理精度问题 11. **矩阵置零(Set Matrix Zeroes)** - 解法:用哈希集合记录需要置零的行列 12. **分糖果(Distribute Candies)** - 解法:通过哈希集合统计糖果种类数 ### 解题技巧总结: 1. **键设计**:根据问题特征设计哈希键,如排序字符串、计算哈希值、构造唯一标识等 2. **空间换时间**:利用哈希表$O(1)$查询特性优化暴力解法 3. **组合结构**:常与滑动窗口、双指针、前缀和等算法结合使用 4. **冲突处理**:在开放寻址法中注意探测策略选择(如二次探测法)[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值