算法学习|Day3 链表操作 虚拟节点 反转链表
今日任务:
数组理论基础,203 移除链表元素(虚拟节点),707设计链表 , 206 反转链表
LeetCode 203 移除链表元素
curr.next=curr.next.next; //核心:取消指向要删除的元素
- 不添加虚拟节点
- 时间复杂度 O(n)
- 空间复杂度 O(1)
先处理头部,再用curr遍历处理后边
class Solution {
public ListNode removeElements(ListNode head, int val) {
while(head!=null&&head.val==val) head=head.next;
ListNode curr=head;
while(curr!=null){
while(curr.next!=null&&curr.next.val==val){
curr.next=curr.next.next;
}
curr=curr.next;
}
return head;
}
}
- 添加虚拟节点方式
- 时间复杂度 O(n)
- 空间复杂度 O(1)
添加头节点前一个为dummy,返回结果就是dummy.next
定义当前节点cur和上一个节点pre
从cur=head,pre=dummy开始遍历
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy =new ListNode(-1,head);
ListNode cur=head;
ListNode pre=dummy;
while(cur!=null){
if(cur.val==val){
pre.next=cur.next;
}else{
pre=cur;
}
cur=cur.next;
}
return dummy.next;
}
}
LeetCode 707 设计链表
设计链表常用操作的实现类
class ListNode{
int val;
ListNode next;
ListNode(){};
ListNode(int val){this.val=val;}
}
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size=0;
head=new ListNode(0);
}
public int get(int index) {
if(index<0||index>=size){return -1;}
ListNode currentNode=head;
for(int i=0;i<=index;i++){
currentNode=currentNode.next;
}
return currentNode.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
if(index>size) return;
if(index<0) index=0;
size++;
ListNode pred = head;
for(int i=0;i<index;i++) pred=pred.next;
ListNode toAdd = new ListNode(val);
toAdd.next=pred.next;
pred.next=toAdd;
}
public void deleteAtIndex(int index) {
if(index<0||index>=size) return;
size--;
if(index==0){head=head.next;return;}
ListNode pred=head;
for(int i=0;i<index;i++){
pred=pred.next;
}
pred.next=pred.next.next;
}
}
LeetCode 206 反转链表
1)双指针解法:
①定义两个指针,一个pre = null,一个cur = head
②循环条件while(cur != null)即cur指针移动到null指针的时候,整个链表已经都遍历一遍了
③定义temp = cur.next;然后翻转指针,即cur.next = pre;然后更新临时指针位置,pre = cur; cur = temp;这几者更新的顺序是固定的。因为若先更新cur.next后报错temp,那么在更新cur的时候,它的位置就不对了。如果,先更新cur后更新pre,那么pre更新后将和cur是一样的位置,故不对
④return pre这个头结点。
2)递归解法:其实其思路与双指针一致,不过是在进行更新pre和cur值的时候进行了递归调用。并且在主函数中调用reverse方法的时候初始值根据双指针的思路------pre = null,cur = head;故调用reverse(null,head);
双指针法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pred = null;
ListNode cur=head;
ListNode temp=null;
while(cur!=null){
temp=cur.next;
cur.next=pred;
pred=cur;
cur=temp;
}
return pred;
}
}
递归法
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null,head);
}
private ListNode reverse(ListNode prev, ListNode cur){
if(cur==null) return prev;
ListNode temp=null;
temp=cur.next;
cur.next=prev;
return reverse(cur,temp);
}
}