链表元素移除:
一段时间没做都有点忘记了, 重点思路就是设置虚拟头节点, 然后再建立一个curr临时节点搜索数据, curr直接等于dummy, 所以就可以利用curr.next来做判断
细节思路:
1. 链表固定的开头: 判断head是否为空
2.需要一个dummyHead,需要一个临时节点cur
3.记住节点的定义就是用 ListNode了
4. 进入while循环,保证cur.next不等于空
5.判断cur.next.val = val, 如果是就改变指针删除,不是就继续找下一个,最后返回dummy.next
因为dummy是一个虚拟头节点,是没有含义的
(while记得是符合条件才执行循环)
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null){
return head;
}
ListNode dummy = new ListNode(666); //虚拟头节点的数无意义
dummy.next = head;
ListNode cur = dummy; //表示上一个节点,用来找数,画图就可以理解了
while(cur.next != null){
if(cur.next.val == val){
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return dummy.next;
}
}
==================================================================================================================================================
设计链表:
这里基础比较薄弱,所以需要对定义进行一些复习,链表需要的东西:
1. Main方法
2. 定义节点:
a. class ListNode-----int val, ListNode next; 等等
b. 构造器:空参和有参
3. 定义链表:
a. class LinkedList---int size, ListNode dummyHead
b.然后开始初始化链表.size = 0, ListNode dummyHead = new dummyHead(0);
开始解题,总体思路: 需要定义一个虚拟头节点, 然后定义一个cur去遍历寻找所需要的值,不管是删除,添加还是查找,只需要改变遍历的参数,让cur停在所需要的地方就可以解决问题.
细节:
1. 一定要判断index是否在链表范围里, 所以不能小于0, 不能大于等于size (因为size总比index小一位数)
2. 判断如果成功, 永远记得写return直接结束啊!!
3.创建新的节点时, 记得ListNode new = .. 保证基础语法正确; 还有cur.val的使用方法
4.永远记住先定义虚拟节点, 然后直接用遍历cur = cur.next去移动cur
5. 对于addIndex方法, index小于0,就直接加头节点, 大于size就直接return;
7.分清楚cur的位置, 当查找时,需要cur直接停在那个数, 所以遍历应该写i <= index; 但是添加和删除的时候, 要把cur停在n前面, 所以i < index;
8.添加细节:停在n前面, 然后新的节点指向n(new.next = cur.next), cur指向新的节点
删除细节: 跨过n改变指针, 停在n前面, cur指向下下个(cur.next = cur.next.next)--如果index是头节点,直接head = head.next
class MyLinkedList {
int size;
ListNode dummyHead;
//初始化链表
public MyLinkedList() {
size = 0;
dummyHead = new ListNode(0);
}
//get方法, 寻找,然后用val返回
public int get(int index) {
if(index < 0 || index >= size){
return -1;
}
//定义一个cur去寻找数字,用遍历就行
ListNode cur = dummyHead;
for(int i = 0; i<= index; i++){ //index和size的定义
cur = cur.next;
}
return cur.val;
}
//添加头部方法
public void addAtHead(int val) {
addAtIndex(0, val);
}
//添加尾部方法
public void addAtTail(int val) {
addAtIndex(size, val);
}
//在第n个前面添加方法
public void addAtIndex(int index, int val) {
if(index > size){
return;
}
if(index < 0){
index = 0;
}
size++;
ListNode add = new ListNode(val);
ListNode pre = dummyHead;
for(int i = 0; i < index; i++){
pre = pre.next; //指针不断前移,停到n前面的位置
}
add.next = pre.next;
pre.next = add;
}
//删除方法
public void deleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
size--;
if(index == 0){
dummyHead = dummyHead.next;
return;
}
ListNode cur = dummyHead;
for(int i = 0; i < index; i++){
cur=cur.next;
}
cur.next = cur.next.next;
}
}
==================================================================================================================================================
反转链表:
这道题分为双指针和递归解法, 双指针解法还是比较容易的.
双指针思路: 需要先定义两个节点,pre, cur,定义完之后直接进入while循环, 条件是(cur != null), 当cur等于null的时候就不要反转了, 然后很简单, 定义next节点, next是用来存储下一个; 开始反转链表, 反转完之后, cur和pre全部集体往后移动.
(记住节点的话用ListNode定义, 不是int了)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
递归写法:
其实就是双指针写法的转换, 首先定义一个reverse方法,来进行递归, 里面传入的参数和双指针一样 reverse(null, head), 因为pre = null; cur = head; base case就是if(cur == null) {return pre}, 对于里面1.还是要写next = cur.next保存数值, 然后 cur.next = pre, 然后再次调用reverse(cur, next) (把pre付给cur, 把cur付给next)
(记住方法里的参数应该填什么就行了, 首先时初始化的值, 然后方法内就是向右移动的值)
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head); //这里就直接给初始值
}
public ListNode reverse(ListNode pre, ListNode cur){
if(cur == null){
return pre;
}
ListNode next = cur.next;
cur.next = pre;
return reverse(cur, next); //全体向前移动
}
}