代码随想录训练营第三天 203.移除链表元素、707.设计链表、206.反转链表
203.移除链表元素
主要思路是记住头结点不能动,否则头结点就丢了
一定要定义两个指针分别指向前结点和当前结点,这样方便删除
//定义单链表结点
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
方法一:设置虚拟头结点,头结点的next指向head,方便删除头结点
- 如果删除的是头结点,那么pre也就代表的是dummy,每次删除头结点后pre.next = cur.next;使得dummy指向新的头结点
- 如果删除的不是头结点,同理由于不删除cur和pre的指向会发生变化,同样可以达到目的
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1,head);
ListNode pre = dummy;
ListNode cur = head;
if (head == null){
return head;
}
while (cur != null){
if (cur.val == val){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
return dummy.next;
}
}
方法二:不设置虚拟头结点
不设置虚拟头结点也就意味着正常的while循环中无法对头结点进行删除,所以再循环结束后只有头结点没有进行判断,再对头结点进行一次判断
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null)
return head;
ListNode pre = head;
ListNode cur = head.next;
while (cur != null){
if (cur.val == val){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
if (head.val == val)
head = head.next;
return head;
}
}
当然也可以先判断头,知道头结点的值与val不等,再进行下面的操作
但是这种方法我做错了,我删除头时忘记判断head不能为空,因为要考虑只删除头就都删没得情况(相当于构造了一个头结点一定不等于val得新的链表)
而都删除之后,也就意味着循环出来可能为空,所以还要进行if判断,我之前把if放在了前面,也不对
class Solution {
public ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val)
head = head.next;
if (head == null)
return head;
ListNode pre = head;
ListNode cur = head.next;
while (cur != null){
if (cur.val == val){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
return head;
}
}
方法三:
只使用一个指针指向头结点,cur所指向的必须是值不等于val的,第一次可以直接指向head是因为在最开始已经进行了处理,新的链表的头结点的值一定不是val,
并且因为不会对cur进行判断,判断的是cur.next的值,这也是第二层是while而不是if的原因,如果是if,一旦新的cur.next的值还是val,那么该结点就没有被处理
class Solution {
public ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val)
head = head.next;
ListNode cur = head;
//当前的头结点的值一定不等于val
while (cur != null){//如果为null,也就不会进入循环
while (cur.next != null && cur.next.val == val){
cur.next = cur.next.next;
}
//if不行,因为cur指向的一定是值不为val的,
//如果是if,那么一次结束后也就意味着如果删除后的新的cur.next的值如果还是val,而cur直接执行cur.next,当前的cur也就没有被判断
cur = cur.next;
}
return head;
}
}
707.设计链表
做的时候一直报错,尤其是在通过索引插入的时候,需要考虑的东西过多,详细的见注解
class ListNode {
int val;
ListNode next;
ListNode(){}
ListNode(int val) {
this.val=val;
}
}
class MyLinkedList {
ListNode head;
MyLinkedList(){
head = new ListNode();
}
public int get(int index) {
if (index < 0){
return -1;
}
ListNode cur = head.next;//此时为第一个结点
int count = 0;
while (cur != null){
if (count++ == index)
return cur.val;
cur = cur.next;
}
return -1;
}
public void addAtHead(int val) {
ListNode node = new ListNode(val);
node.next = head.next;
head.next = node;
}
public void addAtTail(int val) {
ListNode cur = head;
while(cur.next!=null){
cur = cur.next;
}//当前找到的为最后一个结点
ListNode node = new ListNode(val);
cur.next = node;
node.next = null;
}
public void addAtIndex(int index, int val) {
if(index==0) {
addAtHead(val);
}else {
ListNode p = head;
int i = 0;
while(p.next!=null && i < index){//可以防止index越界,出while的条件或者是到最后一个结点或者是索引越界
p = p.next;
i++;
}
if(i == index){
//该条件用来保证上个循环结束并不是由于索引越界,而是达到了要找的位置或者同时满足即达到了要找的位置又到了最后,也就是对尾结点的插入
//相等时为达到索引位置而不是越界,对于最后一个元素来说也是如此,会同时不满足while中的两个条件
ListNode temp = new ListNode(val);
temp.next = p.next;
p.next = temp;
}
}
}
public void deleteAtIndex(int index) {
ListNode pre = head;
ListNode cur = head.next;//当前就是索引为0的
int i =0;
while (cur.next!=null && i<index){
cur = cur.next;
pre = pre.next;
i++;
}
if(i==index){
pre.next = cur.next;
}
}
}
206.反转链表
方法一:使用前后指针
pre指向头结点前,也就是所谓的虚拟头结点,因为要反转,原本真正的head一定指向null
cur第一次指向原来的head结点
最后如果head为空那么返回pre也就为空,只要进入一次循环,哪怕只有一个,返回的pre也是正确的,是第一个结点
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
方法二:使用了递归,但本质和方法一是一样的
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode pre, ListNode cur) {
if (cur == null)
return pre;
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
return reverse(pre, cur);
}
}
e head) {
return reverse(null, head);
}
private ListNode reverse(ListNode pre, ListNode cur) {
if (cur == null)
return pre;
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
return reverse(pre, cur);
}
}