先总结一下数组部分内容:解决问题的主要办法就是利用双指针的思想,不管是滑动窗口还是前缀和。当遇到判断遍历区间需要不断移动时,双指针就会被广泛运用。
新建链表
public class Node<T>{
//节点存储数据
public T Data{get;set;}
//指向下一个节点的引用
public Node<T> Next{get;set;}
//节点的构造函数,用于初始化节点
public Node(T data){
Data=data;
next=null;//初始没有下一个节点,所以为空
}
}
解决针对头结点和其他结点删除操作不一致的问题:创建虚拟头结点(dummyHead)
203.移除链表元素
思路:(具体实现没有什么难度)
-
新建虚拟头节点、用来遍历的节点temp
-
遍历查找目标值val,遇到就用temp跳过
-
最后返回dummyHead.next
public class Solution {
public ListNode RemoveElements(ListNode head, int val) {
ListNode dummyNode = new ListNode(0,head);
ListNode temp = dummyNode;
while(temp.next!=null){
if(temp.next.val==val){
temp.next=temp.next.next;
}
else{
temp=temp.next;
}
}
return dummyNode.next;
}
}
707.设计链表
对链表的基本操作:
-
初始化
-
获取下标结点的值
-
头插、尾插、指定位置插入
-
删除结点
在删除DeleteAtIndex
方法中,一直写错,容易混淆,假设要删除的元素是b,要注意删除需要找到待删除前一个元素a,并将a指向c,所以定义的temp1应该指向虚拟头结点dummyHead而不是dummyHead.next.
public class MyLinkedList {
ListNode dummyNode;
int count;
public MyLinkedList() {
dummyNode=new ListNode(0);
count=0;
}
public int Get(int index) {
if(index<0||index>=count){
return -1;
}
ListNode temp1=dummyNode.next;
for(int i=0;i<index;i++){
temp1=temp1.next;
}
return temp1.val;
}
public void AddAtHead(int val) {
AddAtIndex(0,val);
}
public void AddAtTail(int val) {
AddAtIndex(count,val);
}
public void AddAtIndex(int index, int val) {
if(index>count){
return;
}
ListNode temp1=dummyNode;
for(int i=0;i<index;i++){
temp1=temp1.next;
}
ListNode temp2=new ListNode(val);
temp2.next=temp1.next;
temp1.next=temp2;
count++;
}
public void DeleteAtIndex(int index) {
if(index<0||index>=count){
return;
}
ListNode temp1=dummyNode;
for(int i=0;i<index;i++){
temp1=temp1.next;
}
temp1.next=temp1.next.next;
count--;
}
}
206.反转链表
双指针法:先将cur指向pre,再不断前移pre和cur指针
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode temp1=cur.next;
cur.next=pre;
pre=cur;
cur=temp1;
}
return pre;
}
}
递归:在每次ReverseList过程中,记录ReverseList(1)、ReverseList(2)、ReverseList(3)的值,在head=3时,return3。将这个3值返回给ReverseList函数,接着往下运行head.next.next=head;等语句。这时3→2调转成功,返回ListNode newNode = ReverseList(head.next);语句,将2值返回,接着运行head.next.next=head;等语句,这时3→2→1调转成功。
假设head=2
head.next.next = head; // 即 3.next = 2
head.next = null; // 断开原来的 2 → 3
表达式 | 意思 |
head | 当前节点 |
head.next | 下一节点 |
head.next.next = head | 让“下一节点”的 next 指回当前节点,实现反转 |
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode newNode = ReverseList(head.next);
head.next.next=head;
head.next=null;
return newNode;
}
}
总结:
虽然是二刷,还是有不少地方没有考虑到,一些思路没有理解透彻