数据结构与算法之美
王争
前 Google 工程师
283752 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 81 讲
基础篇 (38讲)
数据结构与算法之美
15
15
1.0x
00:00/00:00
登录|注册

春节7天练 | Day 1:数组和链表

求链表的中间结点
两个有序链表合并
单链表反转
单链表、循环链表、双向链表
两个有序数组合并
大小固定的有序数组
支持动态扩容的数组
连续参与答题并每天留言被精选:每日一课年度会员
回答正确3道及以上:99元专栏通用阅码
参与答题并留言被精选:10元无门槛优惠券
Merge k Sorted Lists
Linked List Cycle I
Missing Positive
Majority Element
Three Sum
链表
数组
春节加油礼包
链表
数组
30个代码实现
分享给朋友
答题活动
LeetCode练习题
数据结构和算法学习成果
后续文章
文章总结

该思维导图由 AI 生成,仅供参考

你好,我是王争。首先祝你新年快乐!
专栏的正文部分已经结束,相信这半年的时间,你学到了很多,究竟学习成果怎样呢?
我整理了数据结构和算法中必知必会的 30 个代码实现,从今天开始,分 7 天发布出来,供你复习巩固所用。你可以每天花一点时间,来完成测验。测验完成后,你可以根据结果,回到相应章节,有针对性地进行复习。
除此之外,@Smallfly 同学还整理了一份配套的 LeetCode 练习题,你也可以一起练习一下。在此,我谨代表我本人对 @Smallfly 表示感谢!
另外,我还为假期坚持学习的同学准备了丰厚的春节加油礼包
2 月 5 日 -2 月 14 日,只要在专栏文章下的留言区写下你的答案,参与答题,并且留言被精选,即可获得极客时间 10 元无门槛优惠券。
7 篇中的所有题目,只要回答正确 3 道及以上,即可获得极客时间 99 元专栏通用阅码。
如果 7 天连续参与答题,并且每天的留言均被精选,还可额外获得极客时间价值 365 元的每日一课年度会员。

关于数组和链表的几个必知必会的代码实现

数组

实现一个支持动态扩容的数组
实现一个大小固定的有序数组,支持动态增删改操作
实现两个有序数组合并为一个有序数组

链表

实现单链表、循环链表、双向链表,支持增删操作
实现单链表反转
实现两个有序的链表合并为一个有序链表
实现求链表的中间结点
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

王争老师的专栏文章以“数据结构和算法”为主题,通过30个代码实现和LeetCode练习题,带领读者复习巩固所学知识。文章内容包括数组和链表的必知必会的代码实现,以及对应的LeetCode练习题。王争老师还为假期坚持学习的同学准备了丰厚的春节加油礼包,包括10元无门槛优惠券、99元专栏通用阅码和365元的每日一课年度会员。读者可以参与答题并留言,获得相应奖励。整个专栏内容将在7天内陆续发布,每天都有测验题目,读者可以根据结果有针对性地进行复习。此外,读者还可以分享测试题给朋友,相互学习交流。整体而言,这篇文章为读者提供了系统的复习计划和丰厚的学习奖励,帮助读者巩固所学知识,提升技术能力。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《数据结构与算法之美》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(117)

  • 最新
  • 精选
  • William
    特地新开了一个git仓库,https://github.com/Si3ver/LeetCode。刷完5道题,思路大致写一下。1.数组三数之和,时间复杂度是O(n^2),先排序,外层i遍历数组,内层左右双指针,寻找两数之和 = -nums[i]。 2. 求数组中出现次数大于一半的数字。复杂度O(n),是利用摩尔投票法。3.求缺失的最小正整数,复杂度O(n),思路是哈希表统计。4.环形链表用快慢指针。5.合并k个有序链表,用的是两两归并,据说用堆会更快,这个有待补充。

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-06
    4
  • 第三题,看这题,我就会想到用快排的思想在一堆数中求第n大。于是乎我就套,先把负数全部移掉,o(n)不影响。然后每轮迭代随机取个数n,比它小的放左边,比他大的放右边。比如说第一轮迭代,左边的数据个数小于n-1那么必然在左边。但这里有个问题是数据是可以重复的,怎么办,想呀想,我就选定n后,开始扫描,如果是1我就放第一个位置,如果是2我就放第二个位置,如果再有1,发现重复了,不用移动了,这样我就能计算小于n大于n的正整数有多少种了,然后就能迭代下去了。当然里面还有些细节,比如如果n很大已超过了数组长度,那说明那个数一定在左边。

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-05
    4
  • Ben
    class Solution(object): def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] 通过hash结构缓存去重值及出现的次数 将值按正负区分, 将正负列表中的数字求和, 判断和的相反数是否仍存在于字典中 """ #将输入列表的值作为索引, 对应出现的次数作为新的字典结构的值 dic = {} for ele in nums: if ele not in dic: dic[ele] = 0 dic[ele] += 1 # 存在3个0的特殊情况 if 0 in dic and dic[0] > 2: rst = [[0, 0, 0]] else: rst = [] pos = [p for p in dic if p > 0] neg = [n for n in dic if n < 0] # 若全为正或负值, 不存在和为0的情况 for p in pos: for n in neg: inverse = -(p + n) if inverse in dic: if inverse == p and dic[p] > 1: rst.append([n, p, p]) elif inverse == n and dic[n] > 1: rst.append([n, n, p]) # 去重: 小于负值且大于正值可以排除掉重复使用二者之间的值 elif inverse < n or inverse > p or inverse == 0: rst.append([n, inverse, p]) return rst def majorityElement(self, nums): """ :type nums: List[int] :rtype: int hash反存值和出现的次数 """ #利用字典表反存值:出现的次数 dic = {} for i in nums: if i not in dic: dic[i] = 1 else: dic[i] +=1 #根据列表获取值最大的索引 vs = list(dic.values()) return list(dic.keys())[vs.index(max(vs))] def firstMissingPositiveFast(self, nums): """ :type nums: List[int] :rtype: int """ n = 1 while n in nums: n +=1 return n

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您10元无门槛优惠券,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-14
    2
  • 赵菁垚
    王老师,请教您一个问题,想参加NOIP c++考这些算法吗?

    作者回复: 也考的

    2019-08-08
    1
  • 神盾局闹别扭
    加油礼包的福利在哪里领呢?

    编辑回复: 运营同学稍后会联系获奖同学哈

    2019-02-18
    1
  • Neo_Zhang
    Three Sum(求三数之和)Go语言: func threeSum(nums []int) [][]int { results := [][]int{} n := len(nums) if n == 0 || n < 3 { return results } sort.Ints(nums) //首先,对数组进行排序 for i := 0; i < n-2; i++ { if i > 0 && nums[i] == nums[i-1] { //如果相邻两个数相等 continue } target := -nums[i] left := i + 1 right := n - 1 for left < right { sum := nums[left] + nums[right] if sum == target { results = append(results, []int{nums[left], nums[right], nums[i]}) left++ right-- for left < right && nums[left] == nums[left-1] { left++ } for left < right && nums[right] == nums[right+1] { right-- } } else if sum > target { right-- } else if sum < target { left++ } } } return results }

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-12
    1
  • 欢乐小熊
    链表篇 1. 翻转单链表 /*翻转单链表*/ void reversalList(Node<int>* head) { Node<int>* p = head; Node<int>* prev = NULL; Node<int>* temp = NULL; while (p) { // 1. 保存要遍历的下一个结点 temp = p->next; // 2. 将 node->next 指向前驱结点 p->next = prev; // 3. 更新前驱结点 prev = p; // 4. 更新下一个要遍历的结点 p = temp; } } 2. 将两个有序的单链表合并 /* 合并两个有序链表, 将 list2 合并到 list1 中 */ Node<int>* mergeOrderList(Node<int>* list1, Node<int>* list2) { // 记录 list2 的头结点 Node<int>* head = list2; // 创建哨兵, 用于处理将 list2 中的元素插入到 list1 头结点前面的情况 Node<int>* sentry = new Node<int>(-1); sentry->next = list1; // 记录 list1 要遍历的元素 Node<int>* node = sentry; Node<int>* temp = NULL; while (node->next && head) { if (node->next->data > head->data) { temp = head->next; head->next = node->next; node->next = head; head = temp; } else { node = node->next; } } // 若 list2 的头结点不为 NULL, 则说明 list1 中的元素提前遍历结束了 // 剩下的 list2 中的元素均比 list1 中的大 // 直接将 list1 的尾结点连接到 list2 的首结点即可 if (head) { node->next = head; } // 释放哨兵结点内存 list1 = sentry->next; sentry->next = NULL; delete(sentry); return list1; } 3. 求单链表的中间结点 /* 查询单链表的中间结点 */ template<typename E> Node<E>* findMidNode(Node<E>* head, Node<E>** mid_node) { if (!head) { return NULL; } Node<E>* fast = head; Node<E>* slow = head; while (fast && fast->next && fast->next->next) { // 快指针走两步 fast = fast->next->next; // 慢指针走一步 slow = slow->next; } *mid_node = slow; }

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-12
    1
  • ALAN
    array answer: import java.util.Arrays; public class Array1 { public int n; public int cur; public static int ary[]; //dynamic expand public static int fix[]; //fixed array public Array1(int size) { n=size; ary=new int [n]; } //dynamic expand public void insert(int ele) { if(cur==ary.length) { ary=Arrays.copyOf(ary, ary.length*2); System.out.println("length:"+ary.length); } ary[cur]=ele; cur++; } //fixed array --add public void add(int ele) { if(cur==fix.length) { return; } fix[cur]=ele; cur++; } //fixed array --delete public void delete() { if(cur==-1) return ; fix[cur]=0; cur--; } //fixed array --update public void update(int index,int ele) { if(index>=0 && index<fix.length) fix[index]=ele; } //merge public int[] merge(int[] a,int[] b ) { int[]c =new int[a.length+b.length]; int j=0,k=0; for(int i=0;i<a.length+b.length;i++) { if(j==a.length) { c[i]=b[k]; k++; continue; }else if(k==b.length){ c[i]=a[j]; j++; continue; } if(a[j]<b[k]) { c[i]=a[j]; j++; }else { c[i]=b[k]; k++; } } return c; } }

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-07
    1
  • acqierement
    自己总结了链表的部分算法,链表算是很简单的数据结构了,只要你心里有一个个节点的概念,必要时画图看一下还是很简单的。 1.单链表反转 反转比较简单,就是要有一个先前节点prev和当前节点cur,要有一个临时节点保存cur的下一个节点(cur.next),否则反转之后你就找不到下一个节点了。然后让head指向前一个节点prev。之后继续移动cur和prev节点进行下一次反转 public ListNode reverse(ListNode head) { ListNode prev = null; ListNode cur = head; while(cur != null) { ListNode temp = cur.next; cur.next = prev; prev = cur; cur = temp; } return prev; } 2.两个有序的链表合并 思路就是自己创建一个链表,每次从两个链表头中找到较小的那个节点,接到自己的那个链表中。说着很简单,但还是有很多细节要注意。 public ListNode mergeTwoLists(ListNode l1,ListNode l2) { if (l1 == null) return l2; if (l2 == null) return l1; ListNode head = new ListNode(0); ListNode cur = head; while(l1 != null && l2 != null) { if (l1.val < l2.val) { cur.next = l1; l1 = l1.next; }else { cur.next = l2; l2 = l2.next; } cur = cur.next; } if (l1 == null) cur.next = l2; if (l2 == null) cur.next = l1; return head.next; } 3.求链表的中间结点(如果是偶数,返回中间两个中靠右的那个) 这个问题就很简单了,环的检测也可以用到这种方法。就是用快慢指针,快的前进两步,慢的前进一步,等到快的指针到结尾时,慢的指针就到了中点。 public ListNode findCenter(ListNode head) { ListNode slow = head; ListNode fast = head; while(fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; }

    编辑回复: 感谢您参与春节七天练的活动,为了表彰你在活动中的优秀表现,赠送您99元专栏通用阅码,我们会在3个工作日之内完成礼品发放,如有问题请咨询小明同学,微信geektime002。

    2019-02-05
    1
  • 陈小白( ´・ᴗ・` )
    这些题,我都做了一遍,除了那个“求缺失的第一个正数“没有相处方法,其它的都是自己做出来了。尤其最后那个”合并 k 个排序链表“,其实以前我也看过一次,当时的想法觉得是一个个取出来,然后排序然后再遍历。学完这堂课之后,看完题目,咦,这不是合并两个链表么?哦,合并多个,怎么处理多个问题?好像可以分治归并,嗯,好像是可以。我了个去,就有那种顿塞的感觉,那种开心。谢谢这门课。也谢谢老师,虽然课程里面还有很多没有明白,不过有些数据结构,算法,细细品味,好爽。

    作者回复: 加油!

    2019-10-06
收起评论
大纲
固定大纲
关于数组和链表的几个必知必会的代码实现
数组
链表
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部