人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

19 | 重新认识数据结构(下):有趣的“链表思维”

你好,我是胡光,欢迎回来。
上节课,我们着重介绍了数据结构的学习方法,就是把数据结构分成两部分进行学习:结构定义结构操作。其中,结构定义是定义数据结构的样子和性质,结构操作就是数据结构的相关功能,并且在操作过程中需要维护相关结构的性质。在这个基础上,我们详细讲了链表的基础结构。
我们经常听到,算法中最有价值的是“算法思维”,其实在数据结构中,最有价值的也是“数据结构思维”。今天呢,我们就看看链表这种具体的数据结构,如何变成一种思维层面的数据结构,辅助我们进行思考。

今日任务

先来看一下今天这 10 分钟的任务吧。首先,我们定义一种数字名称,叫做“快乐数”。所谓快乐数就是经过有限次变换以后,等于 1 的数字。这个变换规则,给出一个非 1 的数字 a ,把它的位数拎出来,求各个位数的平方和,得到一个数字 b,如果数字 b 不是 1,那就对数字 b 的每一位数再做平方和,得到数字 c……经过不停的变换,确定最后能否得到 1。
例如,一开始的数字是 19,经过变换规则 ,得到数字 82;因为不是 1 ,所以接着做变换,就是 ,再做一次变换 ,最后一次做变换 ,得到了 1 以后,停止。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文通过介绍链表的基础结构和操作方法,引出了链表思维在解决“快乐数”判定问题中的应用。作者首先分析了快乐数的计算规则,将快乐数序列中的数字比喻为链表中的节点,强调了快乐数问题可以用链表思维进行改造。进一步讨论了快乐数链表的最大长度和判断快乐数与判断链表中是否有环的等价性。文章以此展示了数据结构在计算机科学中的具体体现,并强调了算法和数据结构的思维变换魅力。通过生动的比喻和深入的思考,读者能够快速了解链表的相关概念和操作方法,为进一步深入学习打下基础。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • 快乐数 leetcode 第 202 题 https://leetcode-cn.com/problems/happy-number/

    作者回复: 对的,就是这个题。

    2020-02-29
    5
  • Cache
    思考题: 之前有见过这个链表成环的拓展题 一、 环的长度 思路: 从相遇节点开始,快慢指针继续走,直至相遇,走的次数就等于环的长度。很好理解,快指针是慢指针速度的一倍,就等价于一个慢指针走一个回路的距离,即是环的长度。 二、 求环的起点 思路:这个问题比较复杂点,不过画个图还是很好理解的。 假设: 起始点到入环点的距离为 D 相遇点到入环点的距离为 S1 环的长度为R 所以: 慢指针走的距离 D + S1 快指针走的距离 D + S1 + nR 又因为 快指针的速度 = 两倍的慢指针的速度 方程为: 2(D + S1) = D + S1 + nR 得: D = nR - S1 从这里可以得出结论,在第一次相遇时,D = R - S1 有了这个结论,只要弄两个指针,一个设置为首节点,一个设置为首次相遇节点,然后每一次依次走一步,直至相遇,就是入环点了。 有了这个思路,代码实现起来,最多只是Debug的过程了。

    作者回复: d(^_^o)

    2020-02-29
    3
    4
  • Objective
    1999999999 这个数字,按照各位平方和来进行计算,得到的下一个数字应该是 (9*9^2 + 1) = 730,也就是说,这个快乐数链表中,节点数量绝对不会超过 731 个 請問為什麼计算得到的下一个数字代表节点数量?

    作者回复: 因为后续所有数字映射到的下一个节点值都不会超过730,也就是说从1999999999这个数字以后,所有节点上的数字都在1到730之间,那你说最多多少个节点呢?

    2020-04-15
    2
  • Geek_79bb26
    1999999999 这个数字,按照各位平方和来进行计算,得到的下一个数字应该是 (9*9^2 + 1) = 730,也就是说,这个快乐数链表中,节点数量绝对不会超过 731 个 请问老师,照这个思路,730以内各个数位平方和最大数应该是699,平方和是81+81+36=198,那么链表节点数是否应该在199=(1+198)个以内;198以内各个数位平方和最大的数是99,平方和是162,那么链表节点数最大应该在164=(2+162)以内,或者可以推出31位整型数据快乐数链表的最大长度是164,谢谢老师,学的有点晚了,不知您是否还浏览这个栏目。

    作者回复: 嗯嗯,你的思路没错的,这里估算一个上界,只是为了说明这个链表的长度是有限的,不会特别长。当我们遍历的时候,一旦超过了我们推导的上界长度,说明这个链表当中存在环。另外,我还会浏览这个栏目,只是回复速度可能不太快。d(^=^o)

    2020-07-13
    1
  • 宋不肥
    int hasCycle(struct Node *head,int* rlong,int* begin) { if (head == NULL) return 0; // p 是慢指针,q 是快指针 struct Node * p = head, q = head; int np = 1,nq = 1; // 每次循环,p 走1步,q 走2步 do { p = p->next; q = q->next; np += 1; nq += 1; if (q == NULL) return 0; q = q->next; nq += 1; } while (p != q && q); *rlong = nq - np; struct Node * two=head; int rangbe = 0; do{ p = p->next; two = two->next; rangbe++; }while(p != two) *begin = rangbe; return 1; }

    作者回复: 非常棒,看得出来,是根据你自己的理解写出来的。所以,还有很多可以优化的地方。(笑哭)

    2020-03-01
    1
  • 1043
    虽然是9次9的平方相乘加,9*9^2为什么不直接写成9^3呢?这样计算机程序不理解吗?可是它会算啊。让运动员跑圈用不用定义“距离”,就跑一圈,即使是环形也不会相遇。另外想问问胡老师这个null地址是最终目的吗?并且是定点指向一定要去往的地址吗?如果到不了null地址就知道有环。这需要定义最大值吗?不然如何停下呢?

    作者回复: 快慢指针,就是用来解决有环情况下,如何停下来的问题的。如果两个指针相遇了,说明有环,如果快指针最先跑到了null地址,说明链表无环,是一个直道。

    2020-04-15
  • 宋不肥
    示例代码中,p 和 q 应该是结构体指针类型而不是 int 类型吧

    作者回复: 恩,对的,是个笔误。

    2020-02-29
  • 公众号:程序员大兵
    ```go func isHappy(n int) bool { var nextNum = func (n int) int { next := 0 for n > 0 { t := n % 10 next += t * t n /= 10 } return next } p, q := n, n for { p, q = nextNum(p), nextNum(nextNum(q)) if p == q { break } } return q == 1 } ```
    2023-12-22归属地:北京
  • Geek_wilbur
    #include <stdio.h> #include <stdlib.h> typedef struct { int input; int output; } data_st_t;; data_st_t datas[800]; int calc(int in) { int out = 0; int digit; digit = in%10; while (in) { out += (in%10)*(in%10); in /=10; } return out; } int main() { int num = 0; int i; int val; printf("input num:"); fflush(stdout); scanf("%d", &num); if (num <= 0) { return -1; } while(1) { val = calc(num); printf("%d->%d\n", num, val); if (val == 1) { printf("happy num\n"); break; } if (datas[val].output) { printf("loop, unhappy\n"); break; } datas[val].input = num; datas[val].output = val; num = val; } return 0; }
    2023-02-03归属地:广东
  • 马建华
    找环起始点的方法:定义快慢指针为fast = head->next, slow = head. 然后让他们相遇。相遇后,头结点指针和慢指针同时移动,走到head = slow->next停下。此时head指向的就是环的起点。 这题可以用数学证明出来。假设链表非环部分的长度是x1, 环的长度是x2, slow的步长是d,fast的步长是2d,总共走了m步,那么在slow和fast相遇时,前者走了md= x1 + L, 后者走了m2d = x1 -1 + x2 + L, 因此我们有x1 + 1 = x2 - L,也就是说,head和slow要相遇的距离相差1,也就是head走到环起始点时,slow肯定相差一个步长,因此head = slow->next就是循环出口
    2021-04-18
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部