链表的定义,非常重要,要会写:
public class ListNode {
// 结点的值
int val;
// 下一个结点
ListNode next;
// 节点的构造函数(无参)
public ListNode() {
}
// 节点的构造函数(有一个参数)
public ListNode(int val) {
this.val = val;
}
// 节点的构造函数(有两个参数)
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
我这个逻辑上是有问题的,就是你如果是进的if(post.val == val)成立,cur应该是不动的,应该是post动继续去判断他后面的,而不是都往后移动一位,所以下面的就出错了
最后修改过后的正确的不用虚拟头节点的代码:
class Solution {
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val){
head = head.next;
}
if(head == null)
return head;
ListNode cur = head;
ListNode post = head.next;
while(post != null){
if(post.val == val){
cur.next = post.next;
}else{
cur = post;
}
post = post.next;
}
return head;
}
}
用虚拟头节点的方法:
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null)
return head;
ListNode dummy = new ListNode(-1, head);
ListNode pre = dummy;
ListNode cur = head;
while(cur != null){
if(cur.val == val){
pre.next = cur.next;
}else{
pre = cur;
}
cur = cur.next;
}
return dummy.next;
}
}
这里有一个细节是, ListNode dummy = new ListNode(-1, head);是定义了新的链表,然后第一个值是-1,然后到head,而ListNode pre = dummy;是定义了一个虚拟的头结点,方便去调动位置删减,最后返回的还得是dummy.next。
707.设计链表
建议: 这是一道考察 链表综合操作的题目,不算容易,可以练一练 使用虚拟头结点
题目链接/文章讲解/视频讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
很长的代码片段,对基础的掌握很关键
public class ListNode{
int val;
ListNode next;
public ListNode(){
}
public ListNode(int val){
this.val = val;
}
public ListNode(int val,ListNode next){
this.val = val;
this.next = next;
}
}
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 cur = head;
for(int i = 0 ; i<=index ; i++){
cur = cur.next;
}
return cur.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 || index < 0) {
return ;
}
size++;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode Add = new ListNode(val);
Add.next = pred.next;
pred.next = Add;
}
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;
}
}
206.反转链表
建议先看我的视频讲解,视频讲解中对 反转链表需要注意的点讲的很清晰了,看完之后大家的疑惑基本都解决了。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre;
pre = null;
ListNode cur;
cur = head;
while(cur != null){
//保存cur指针
ListNode temp = cur.next;
cur.next =pre;
//移动指针
pre = cur;
cur =temp;
}
return pre;
}
}
视频讲的确实牛逼通透,关键就在于要花图去理清楚思路再写,代码不难,主要是思路
递归真的牛逼!
一个是要另外定义一个函数来实现递归,因为主函数只有head,然后是弄清楚结束递归的条件,还有循环的形式:
class Solution {
public ListNode reverseList(ListNode head) {
return rever(null,head);
}
public ListNode rever(ListNode pre , ListNode cur){
if(cur == null){
return pre;
}
ListNode temp ;
temp = cur.next;
cur.next = pre;
return rever(cur,temp);
}
}