203.移除链表元素
class Solution {
public ListNode removeElements(ListNode head, int val) {
//如果是头指针
while(head!=null&&head.val==val){
head=head.next;
}
if(head==null){
return head;
}
ListNode p=head;
ListNode q=head.next;
while(q!=null){
if(q.val==val){
p.next=q.next;
q=p.next;
}else{
p=p.next;
q=q.next;
}
}
return head;
}
}
我的算法没有采用虚拟头节点,采用虚拟头节点会让代码简单很多,但是我没用使用,是想锻炼一下。
这个没什么好说的,就是删除链表节点,待删除节点的前一个节点指向删除节点的下一个节点。
若是头指针直接head指针后移即可。
707.设计链表
class MyLinkedList {
class Node{
int val;
Node next;
public Node(){}
public Node(int val){
this.val=val;
}
public Node(int val,Node next){
this.val=val;
this.next=next;
}
}
int length;
Node head;
Node tail;
public MyLinkedList() {
length=0;
head=null;
tail=null;
}
//改一下
public int get(int index) {
if(index>=length){return -1;}
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
return p.val;
}
public void addAtHead(int val) {
Node newHead=new Node(val);
if(head==null){
tail=newHead;
}else{
newHead.next=head;
}
head=newHead;
length++;
}
public void addAtTail(int val) {
Node newTail=new Node(val);
if(head==null){
head=newTail;
}else{
tail.next=newTail;
}
tail=newTail;
length++;
}
public void addAtIndex(int index, int val) {
if(index>length){return;}
Node p=head;
if(index==0){
addAtHead(val);
}else if(index==length){
addAtTail(val);
}else{
for(int i=0;i<index-1;i++){
p=p.next;
}
Node newNode=new Node(val,p.next);
p.next=newNode;
length++;
}
}
public void deleteAtIndex(int index) {
if(index>=length){return;}
if(index==0){
head=head.next;
}else{
Node p=head;
for(int i=0;i<index-1;i++){
p=p.next;
}
if(p.next==tail){
tail=p;
p.next=null;
}else{
p.next=p.next.next;
}
}
length--;
}
}class MyLinkedList {
class Node{
int val;
Node next;
public Node(){}
public Node(int val){
this.val=val;
}
public Node(int val,Node next){
this.val=val;
this.next=next;
}
}
int length;
Node head;
Node tail;
public MyLinkedList() {
length=0;
head=null;
tail=null;
}
//改一下
public int get(int index) {
if(index>=length){return -1;}
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
return p.val;
}
public void addAtHead(int val) {
Node newHead=new Node(val);
if(head==null){
tail=newHead;
}else{
newHead.next=head;
}
head=newHead;
length++;
}
public void addAtTail(int val) {
Node newTail=new Node(val);
if(head==null){
head=newTail;
}else{
tail.next=newTail;
}
tail=newTail;
length++;
}
public void addAtIndex(int index, int val) {
if(index>length){return;}
Node p=head;
if(index==0){
addAtHead(val);
}else if(index==length){
addAtTail(val);
}else{
for(int i=0;i<index-1;i++){
p=p.next;
}
Node newNode=new Node(val,p.next);
p.next=newNode;
length++;
}
}
public void deleteAtIndex(int index) {
if(index>=length){return;}
if(index==0){
head=head.next;
}else{
Node p=head;
for(int i=0;i<index-1;i++){
p=p.next;
}
if(p.next==tail){
tail=p;
p.next=null;
}else{
p.next=p.next.next;
}
}
length--;
}
}
这个设计链表我采用了内部类的方式定义了一个Node
而在链表设计上,我通过给链表赋head tail length 使得代码量减小,当然也让代码需要考虑的事情变多了,比如修改删除节点时tail指针的变化。
其中有一次我把length++写在了判断条件外面,导致尾插时会使length数据多加一,然后删除数据的时候链表就出问题了。通过Debug找了出来,这个题主要还是代码量多,一次性写出来不debug很容易出错。
206.反转链表(这个我忘了mark一下后面复习)
反转链表这个题我写了三种不同思路
常规双指针反转
class Solution {
public ListNode reverseList(ListNode head) {
ListNode q;
ListNode p=head;
ListNode pre=null;
while(p!=null){
//记录p.next
q=p.next;
//反转
p.next=pre;
//更新
pre=p;
p=q;
}
return pre;
}
}
通过q指针去记录要反转的节点p的下一个节点,防止让p.next指向pre时节点丢失。
最后当p指针==null时,pre指针就是反转好的链表。
递归实现正向反转
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null){return head;}
return func(head,null);
}
public ListNode func(ListNode head,ListNode pre){
ListNode p=head.next;
head.next=pre;
ListNode ans;
if(p!=null){
ans=func(p,head);
return ans;
}
return head;
}
}
正向递归就是将前面的链表作为已反转链表然后传递给下一次递归,将该次递归的节点指向这个已反转链表(记得记录这个节点的next作为参数传递给下一次递归)。当遇到head的下一个节点是null时,反转完成。将该节点指针返回,而前面的递归只需要将方法收到的返回值继续返回即可。
递归实现反向反转
class Solution {
public ListNode reverseList(ListNode head) {
if(head!=null){
ListNode p=reverseList(head.next);
if(p==null){return head;}
//1.找到链表尾
ListNode q=p;
while(q.next!=null){
q=q.next;
}
//2.将自己(head)插入链表尾
head.next=null;
q.next=head;
//3.返回反转的链表
return p;
}
return head;
}
}
这个方法要求的时间复杂度比上面要高,是我第一次写出来的,有点垃圾哈哈。
其实这个也没啥好说的,先递归到链表末尾再进行操作,先遍历已反转链表(方法的返回值)到末尾然后将此次递归的head节点插在末尾。
今日总结
移除链表元素和设计链表都没啥问题,反而是这个反转链表之前做过没有理解,今天再次做的时候就找不到北了,做出来的时从后往前反转的,时间复杂度高了且更麻烦,需要特殊记忆一下。