赞
踩
提示:算法学习不努力,秋招春招是弟弟
提示:以下是本篇文章正文内容来自极客时间系列教程,下面案例可供参考
Array
:在内存中,数组是一块连续的区域
Linked List
:链表在内存中可以存在任何地方,不要求连续。
Array
由于内存连续
的特点,插入和删除
往往需要一个个往后挪位置,除非你插入的是最后一个位置。
时间复杂度
Array
• Access: O(1)
• Insert: 平均 O(n)
• Delete: 平均 O(n)
每一个节点都保存了下一个数据的内存地址,通过这个地址找到下一个数据。
可以知道,这种数据结构的查找需要一个一个节点的寻址下去,效率是比较低的
插入操作
先让新增节点的下一节点指针域指向原有的尾部,再挂到要插入的节点
删除操作
直接跳过要删除的节点,指向下一节点即可
时间复杂度
时间复杂度
space O(n)
prepend O(1)
append O(1)
lookup O(n)
insert O(1)
delete O(1)
– | 数组(Array) | 链表(Linked List) |
---|---|---|
读取 | O(1) | O(n) |
插入 | O(n) | O(1) |
删除 | O(n) | O(1) |
数组的优点
:
数组的缺点
链表的优点
链表的缺点
自定义ListNode
package LinkedList; public class ListNode { //数据域 public int val; //下一节点域 public ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } }
迭代思路
递归思路
package com.gdpu.day1; import LinkedList.ListNode; /** * 反转链表 * https://leetcode.com/problems/reverse-linked-list/ * */ public class NO_206_ReverseLinkedList { //迭代解法 public ListNode reverseList(ListNode head){ //前面的指针 ListNode prev =null; //当前指针 ListNode curr = head; //当还没到最后一个指针 while (curr!=null){ //反转一个的操作 ListNode next = curr.next; curr.next = prev; //向后移动 prev =curr; curr =next; } return prev; } //递归解法 public ListNode recursive(ListNode head){ //递归终止条件 //head是null,或者已经到最后一个节点,出口 if (head ==null ||head.next==null){ return head; } ListNode p = recursive(head.next); //一个环形指回前面 head.next.next = head; //把目前的下一个设为null head.next =null; return p; } }
递归思路
利用栈的先进后出的特性
package com.gdpu.day1; import LinkedList.ListNode; import java.util.Stack; public class NO_24_swapPairs { /** * 递归出口:当前节点或者下一个节点为空,返回 * 方法内容:当前节点next,指向当前节点,指针互换 * 返回值:返回交换完成的节点 */ public ListNode swapPairsRecursive(ListNode head) { //递归的终止条件 if(head==null || head.next==null) { return head; } //假设链表是 1->2->3->4 //这句就先保存节点2 ListNode tmp = head.next; //继续递归,处理节点3->4 //当递归结束返回后,就变成了4->3 //于是head节点就指向了4,变成1->4->3 head.next = swapPairsRecursive(tmp.next); //将2节点指向1 tmp.next = head; return tmp; } //用栈 public ListNode swapPairsByStack(ListNode head) { if(head==null || head.next==null) { return head; } //用stack保存每次迭代的两个节点 Stack<ListNode> stack = new Stack<ListNode>(); ListNode p = new ListNode(-1); ListNode cur = head; //head指向新的p节点,函数结束时返回head.next即可 head = p; while(cur!=null && cur.next!=null) { //将两个节点放入stack中 stack.add(cur); stack.add(cur.next); //当前节点往前走两步 cur = cur.next.next; //从stack中弹出两个节点,然后用p节点指向新弹出的两个节点 p.next = stack.pop(); p = p.next; p.next = stack.pop(); p = p.next; } //注意边界条件,当链表长度是奇数时,cur就不为空 if(cur!=null) { p.next = cur; } else { p.next = null; } return head.next; } }
利用set集合的不可重复的特性
public boolean hasCycle(ListNode head) {
Set<ListNode> seen = new HashSet<ListNode>();
while (head != null) {
if (!seen.add(head)) {
return true;
}
head = head.next;
}
return false;
}
快慢双指针迭代
/** * 快慢指针迭代 */ public boolean hasCycle1(ListNode head) { //如果是空或者只有一个节点 if (head == null || head.next == null) return false; //起点差一步 ListNode slow = head; ListNode fast = head.next; //起点快,步数快,还能相遇肯定有环 while (slow != fast) { if (fast == null || fast.next == null) { return false; } //慢的走一步 slow = slow.next; //快的走两步 fast = fast.next.next; } return true; }
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null){
return null;
}
Set<ListNode> seen = new HashSet<>();
while(head!=null){
if(!seen.add(head)){
return head;
}
head = head.next;
}
return null;
}
/** * 用双指针 */ public ListNode detectCycle1(ListNode head) { ListNode fast = head, slow = head; while (true) { if (fast == null || fast.next == null) return null; fast = fast.next.next; slow = slow.next; if (fast == slow) break; } fast = head; while (slow != fast) { slow = slow.next; fast = fast.next; } return fast; }
递归解决
package com.gdpu.day1; import LinkedList.ListNode; import java.util.List; public class NO_25_reverseKGroup { public ListNode reverseKGroup(ListNode head, int k) { if (head == null || head.next == null) { return head; } ListNode tail = head; for (int i = 0; i < k; i++) { //剩余数量小于k的话,则不需要反转。 if (tail == null) { return head; } tail = tail.next; } // 反转前 k 个元素 ListNode newHead = reverse(head, tail); //下一轮的开始的地方就是tail head.next = reverseKGroup(tail, k); return newHead; } /** * 反转某段链表 */ private ListNode reverse(ListNode head,ListNode tail){ ListNode prev=null; ListNode curr = head; while (curr!=tail){ ListNode next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。