分享一个延长机械硬盘寿命的小技巧——少用Windows搜索

chengsenw 项目开发评论1阅读模式

分享一个延长机械硬盘寿命的小技巧——少用Windows搜索

分享一个延长机械硬盘寿命的小技巧——少用Windows搜索

楔子

大家好,我是张桃狮。

我单位用的办公电脑还是十几年前的配置,只有安装WIN10系统的C盘是固态硬盘,D盘还是一块机械硬盘。

因为D盘比较大,我平时都是用D盘存文件。

日积月累,D盘存储了海量的文件。

每次我在D盘搜文件,硬盘灯都会亮上很久,让我担心硬盘会不会突然挂掉。

我估计Windows搜索是通过实时遍历磁盘目录来找文件的,这样做的好处是实时同步,缺点是太慢了。

从XP、WIN7到WIN10,Windows搜索似乎一直都是这么干的。

如果你也有这种烦恼,强烈建议试试Everything,这款神仙工具直接把找文件的痛苦煎熬变成秒出结果的快乐体验。

https://www.voidtools.com/zh-cn/

上面是Everything的官方网址,这个软件是免费使用的。

下面讲讲Everything是如何做到秒出结果的。

当Everything第一次启动时,会直接访问NTFS硬盘的主文件表(MFT)。

MFT是NTFS的核心结构,里面集中存储了该分区下所有文件和文件夹的关键元数据——包括文件名、存储路径、创建/修改时间,且这些数据是按固定结构有序存储的,不是分散在磁盘各处。Everything只提取这些元数据,完全不读取文件内容,然后将这些信息整理成一个轻量化的索引库,直接加载到电脑内存中。

这个过程速度极快,因为它是读取一个连续的系统结构,而非像Windows搜索那样逐个目录遍历文件,1TB的NTFS硬盘通常几十秒就能完成初始化。

电脑使用过程中,文件会不断被新建、删除、重命名,Everything不需要重新扫描整个硬盘来更新索引,而是靠监听系统的更新序列号码日志(USNJournal)。

USNJournal是NTFS系统自带的日志文件,会自动记录所有文件的变动操作。

Everything会实时读取这个日志,一旦检测到文件变动,就直接在内存里的索引库中做对应修改——新增文件就添加一条索引记录,删除文件就移除对应记录,全程只操作内存,不触发大规模磁盘读写。

当你在Everything搜索框输入关键词时,它不会去访问硬盘,而是直接在内存里的索引库中做匹配查询。

内存的读写速度比硬盘快上万倍,所以输入关键词的瞬间就能完成匹配,给出搜索结果,这也是为什么用Everything搜索时,硬盘灯基本不会闪烁——全程几乎没有磁盘IO操作。

俗话说硬盘有价,资料无价。

听说最近电脑硬件价格上涨的厉害,大家更应该注意自己电脑里机械硬盘的寿命。

我觉得用Everything替代Windows搜索,是一个零成本延长硬盘使用寿命的好方法。

大家觉得呢?

闲话讲完,咱们继续刷题学编程。

力扣202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。

然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。

如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19

输出:true

解释:

12 + 92 = 82

82 + 22 = 68

62 + 82 = 100

12 + 02 + 02 = 1

示例 2:

输入:n = 2

输出:false

提示:

1 <= n <=  - 1

我的思路

写一个循环,如果计算结果为1,就返回True,很容易。

但是示例2中,n=2就无法测试通过了。

因为2的数字平方和结果为2、4、16、37、58、89、145、42、20、4、16……

当结果再次出现4后,后面的就是无限循环,永远也不会出现1了。

这时就应该返回False。

我新建了一个集合,将所有计算结果记录下来,并用if判断是否出现无限循环。

这样虽然可以通过大部分测试,但是我忽略了n=1的特殊情况。

还是用老办法,用if条件把特殊情况绕过去,最后提交通过了。

class Solution:    def isHappy(self, n: int) -> bool:        ret=0        ret_set={n}        while ret != 1:            ret=0            for i in str(n):                ret += int(i)*int(i)            if ret in ret_set and ret != 1:                return False            ret_set.add(ret)            n=ret        return True

力扣提交通过,时间复杂度和空间复杂度都是O (log n)。

官方题解

方法一:用哈希集合检测循环

class Solution:    def isHappy(self, n: int) -> bool:        def get_next(n):            total_sum = 0            while n > 0:                n, digit = divmod(n, 10)                total_sum += digit ** 2            return total_sum        seen = set()        while n != 1 and n not in seen:            seen.add(n)            n = get_next(n)        return n == 1

官方题解方法一和我的代码思路差不多,时间和空间复杂度也是O (log n)

不过官方题解没有用字符串循环,而是对n除以10,取商和余数。

divmod(a, b) 会接收两个数字参数 a(被除数)和 b(除数),同时返回一个包含商和余数的元组 (商, 余数),等价于 (a // b, a % b),但只需要一次计算,效率更高。

发现一个小技巧,官方题解方法一的代码没有加class Solution:,我增加class Solution:后,全选下面的代码,按tab键瞬间就给所有行增加了4个空格。

这个技巧在VS Code中也有效,以前的我都是手动给每行加空格,后悔没有早点发现。

方法二:快慢指针法

class Solution:    def isHappy(self, n: int) -> bool:        def get_next(number):            total_sum = 0            while number > 0:                number, digit = divmod(number, 10)                total_sum += digit ** 2            return total_sum        slow_runner = n        fast_runner = get_next(n)        while fast_runner != 1 and slow_runner != fast_runner:            slow_runner = get_next(slow_runner)            fast_runner = get_next(get_next(fast_runner))        return fast_runner == 1

将无限循环想象为一个环形链表,如何判断链表有环,可以用弗洛伊德龟兔赛跑算法 / Floyd's Tortoise and Hare Algorithm。

让慢指针每次走一步,快指针每次走两步,如果有环,快慢指针肯定会相遇。

之前我一直以为这个算法只适合链表,现在看来我有点小瞧它了。

使用弗洛伊德龟兔赛跑算法来做这道题的好处是,不需要占用宝贵的内存空间来存储之前的计算结果,空间复杂度变为O(1)。

时间复杂度还是O (log n)。

方法三:数学

class Solution:    def isHappy(self, n: int) -> bool:        cycle_members = {4, 16, 37, 58, 89, 145, 42, 20}        def get_next(number):            total_sum = 0            while number > 0:                number, digit = divmod(number, 10)                total_sum += digit ** 2            return total_sum        while n != 1 and n not in cycle_members:            n = get_next(n)        return n == 1

这个集合 {4, 16, 37, 58, 89, 145, 42, 20}是怎么来的,说实话我有点看不懂。

但是我想到一个证明的方法。

题目有提示1 <= n <=  - 1

我只需要将1到 - 1的所有整数都按照方法一算一遍,并将非快乐数得到的计算结果集合求交集,说不定可以看出端倪。

class Solution:    def isHappy(self, n: int) -> bool:        def get_next(n):            total_sum = 0            while n > 0:                n, digit = divmod(n, 10)                total_sum += digit ** 2            return total_sum        seen = set()        while n != 1 and n not in seen:            seen.add(n)            n = get_next(n)        if n != 1:            return seensolution=Solution()result_sets = []for i in range(1,2**31):    if solution.isHappy(i) :        result_sets.append(solution.isHappy(i))final_intersection = result_sets[0]for s in result_sets[1:]:    final_intersection &= sprint(final_intersection)

结果发现算力不够,长时间得不到计算结果,只好将计算范围调小到range(1,2**11)。

在VS Code中运行得到的结果是{4, 37, 42, 16, 145, 20, 89, 58}

这8个数与力扣官方题解方法三中的cycle_members是一样的。

我尝试将计算范围调整到range(1,2**21),运行一段时间后,得到结果也是{4, 37, 42, 16, 145, 20, 89, 58}。

再大我就没尝试了,计算时间太久了,等不及。

我忽然发现我不用尝试这么大的数字。

因为经过第一次计算以后,数字长度就会几何级的变短。

print(len(str(2**31-1)))

结果是10

10位数最大的数是9999999999,经过第一轮计算后会得到810,它已经变成一个3位数了。

其他小于9999999999的数,经过第一轮计算后不可能大于810。

我只需要用1-810来计算结果交集就好了。

将range(1,2**11)修改为range(1,811),可以很快得到计算结果{4, 37, 42, 16, 145, 20, 89, 58}。

看来在本题的数字范围内,这8个数在所有非快乐数的计算结果中都会出现。

而且只要出现其中一个数,就会进入这8个数的循环。

比如4、16、37、58、89、145、42、20、4、16……,所以方法三的计算结果是正确的。

官方题解方法三的时间复杂度是O(logn),空间复杂度是O(1)。

我是个编程爱好者,小白级别的,如果你跟我一样希望通过力扣刷题,学习各种奇妙的算法,可以关注我,大家一起学习。

 
chengsenw
  • 本文由 chengsenw 发表于 2026年1月30日 02:16:31
  • 转载请务必保留本文链接:https://www.gewo168.com/10874.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: