今日任务
Java链表理论基础
链表在大一下中的数据结构学过,就不再过多赘述了
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.移除链表元素
原链表删除元素
* 不添加虚拟节点and pre Node方式
* 时间复杂度 O(n)
* 空间复杂度 O(1)
class Solution {
public ListNode removeElements(ListNode head, int val) {
//先判断是不是头节点
while(head!=null&&head.val==val){//持续移除的过程用while,且以防出现1,1,1,1这样的链表
head=head.next;
}
ListNode cur=head;//要删除cur的话,需要指针指头结点
while(cur!=null&&cur.next!=null)//不能操作空指针,且要删除的指针也不能为空
{
if(cur.next.val==val)
cur.next=cur.next.next;
else
cur=cur.next;//若不相等,继续向下走
}
return head;
}
}
添加pre Node
public ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val) {
head = head.next;
}
// 已经为null,提前退出
if (head == null) {
return head;
}
// 已确定当前head.val != val
ListNode pre = head;
ListNode cur = head.next;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return head;
}
添加虚拟头节点
class Solution {
public ListNode removeElements(ListNode head, int val) {
//新增虚拟头节点是为了统一所有结点的删除和增加规则
//定义一个结点使其称为新的头节点
ListNode dummy=new ListNode();
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;//为什么不return head,因为有可能被删掉了
}
}
707.设计链表
注意
各种操作的非法情况,
单链表的功能
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
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) {
ListNode cur=head;
//如果index非法,返回-1
if (index < 0 || index >= size) {
return -1;
}
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) {
return;
}
if (index < 0) {
index = 0;
}
ListNode toadd=new ListNode(val);
ListNode cur=head;
//长度要加长
size++;
for(int i=0;i<index;i++){
cur=cur.next;
}
toadd.next=cur.next;
cur.next=toadd;
}
public void deleteAtIndex(int index) {
if (index < 0||index >=size) {
return;
}
size--;
if (index ==0) {
head=head.next;
return;
}
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
cur.next=cur.next.next;
}
}
双链表
class ListNode {
int val;
ListNode next;
ListNode prev;
ListNode(){}
ListNode(int val) {
this.val=val;
}
}
class MyLinkedList {
int size;
ListNode head;
ListNode tail;
public MyLinkedList() {
//初始化操作
this.size = 0;
this.head = new ListNode(0);
this.tail = new ListNode(0);
//这一步非常关键,否则在加入头结点的操作中会出现null.next的错误!!!
head.next=tail;
tail.prev=head;
}
public int get(int index) {
ListNode cur=head;
//如果index非法,返回-1
if (index < 0 || index >= size) {
return -1;
}
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) {
return;
}
if (index < 0) {
index = 0;
}
ListNode toadd=new ListNode(val);
ListNode cur=head;
//长度要加长
size++;
for(int i=0;i<index;i++){
cur=cur.next;
}
toadd.next=cur.next;
cur.next.prev=toadd;
cur.next=toadd;
toadd.prev=cur;
}
public void deleteAtIndex(int index) {
if (index < 0||index >=size) {
return;
}
size--;
if (index ==0) {
head=head.next;
return;
}
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
cur.next=cur.next.next;
cur.next.prev=cur;
}
}
206.反转链表
思路
有两种解法:双指针和递归
双指针
cur循环指针,pre在cur前,一开始cur指向后一个,pre使其指向cur前一个
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;//反转链表,头会变成尾,所以应该pre指向空
ListNode temp=null;
while(cur!=null){
temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
}
递归解法
一个思路,只是用递归代替了循环
class Solution {
public ListNode reverse(ListNode cur,ListNode pre){
if(cur==null)
return pre;
ListNode temp=null;
temp=cur.next;
cur.next=pre;
return reverse(temp,cur);
}
public ListNode reverseList(ListNode head) {
return reverse(head,null);
}
}