代码随想录算法训练营Day03
链表
删除链表元素
原地删除和虚拟头结点(DummyNode)
- 原地删除(头结点和其他结点的操作不一致),也可以两个指针,一个表示当前结点,一个表示当前节点的上一个结点
//while循环中的条件是怎么来的?下面要取他的值,如果为空则异常
class Solution {
	public ListNode removeElements(ListNode head, int target) {
		while (head != null && head.val == target) {//这里用while防止链表中的元素全都是要删除的值
			head = head.next;//Java中不支持->这种操作,只支持.操作结构的分量
		}
		ListNode current = head;//上面已经判断了头指针不是要删除的结点,那为什么这里的current是从head开始?这里的current实际上是要删除的结点的前一个结点
		while(current!=null && current.next!=null){//这里不等于null是防止下面对null取分量导致异常出现
			if(current.next.val == target){
				current.next = current.next.next;
			}else{
				current = current.next;
			}
		}
		return head;
	}
}
- 虚拟头结点
class Solution {
	public ListNode removeElements(ListNode head, int target) {
		ListNode dummyNode = new ListNode();
		dummyNode.next = head;
		ListNode current = dummyNode;
		while(current!=null&¤t.next!=null){//安全性检查,防止对空指针进行操作,根据要求,只需要循环到链表的倒数第二个结点即可
			if(current.next.val==target){
				current.next = current.next.next;
			}else{
				current = current.next;
			}
		}
		return dummyNode.next;
	}
}
- 递归方法解决(找好递归出口和递归体)不大明白啊
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        // 假设 removeElements() 返回后面完整的已经去掉val节点的子链表
        // 在当前递归层用当前节点接住后面的子链表
        // 随后判断当前层的node是否需要被删除,如果是,就返回
        // 也可以先判断是否需要删除当前node,但是这样条件语句会比较不好想
        head.next = removeElements(head.next, val);
        if (head.val == val) {
            return head.next;
        }
        return head;
        // 实际上就是还原一个从尾部开始重新构建链表的过程
    }
}
设计链表
- 在
get、addAtIndex和deleteAtIndex方法中,使用for循环遍历链表。这是因为这些操作需要遍历到特定的索引位置,循环次数是已知的。for循环在这种情况下更加简洁和直观。- 在
addAtTail方法中,使用while循环遍历到链表的末尾。这是因为我们不知道链表的具体长度,需要一直遍历直到找到最后一个节点。
- current = dummyHeadNode:
当我们需要操作链表的头部或者在任意位置插入节点时,通常将current初始化为dummyHeadNode。这样做可以统一处理头节点和其他节点,简化边界情况的处理- current = dummyHeadNode.next:
当我们只需要遍历或访问实际的链表元素时,通常将current初始化为dummyHeadNode.next。这样可以直接从链表的第一个实际节点开始操作
- 注意判断index是否合法
class MyLinkedList {  
    private int size;  
    private ListNode dummyHeadNode;  
  
    public MyLinkedList() {  
        size = 0;  
        dummyHeadNode = new ListNode(0);  
    }  
  
    public int get(int index) {  
        //get:用for循环,current指向dHN.next  
        if(index<0||index>size-1){  
            return -1;  
        }  
        ListNode current = dummyHeadNode.next;  
        for(int i = 0;i < index;i++){  
            current = current.next;  
        }  
        return current.val;  
    }  
  
    public void addAtHead(int val) {  
        ListNode newNode = new ListNode(val);  
        newNode.next = dummyHeadNode.next;  
        dummyHeadNode.next = newNode;  
        size++;  
    }  
  
    public void addAtTail(int val) {  
        addAtIndex(size,val);  
    }  
  
    public void addAtIndex(int index, int val) {  
        //for循环遍历,为了保证头结点也适用这个插入函数,因此current指向dHN  
        if(index<0||index>size){  
            return;  
        }//注意这里的判断语句  
        ListNode newNode = new ListNode(val);  
        ListNode current = dummyHeadNode;  
        for(int i = 0;i < index;i++){  
            current = current.next;  
        }  
        newNode.next = current.next;  
        current.next = newNode;  
        size++;  
    }  
  
    public void deleteAtIndex(int index) {  
        if(index<0||index>size-1){  
            return;  
        }//注意这里的判断语句  
        //for循环遍历,为了保证头结点也适用这个插入函数,因此current指向dHN  
        ListNode current = dummyHeadNode;  
        for(int i = 0;i < index;i++){  
            current = current.next;  
        }  
        current.next = current.next.next;  
        size--;  
    }  
}
反转链表
逐个修改指针即可
- 循环法
class Solution {
	public ListNode reverseList(ListNode head) {
		ListNode prior = null;
		ListNode current = head;
		while(current != null){
			ListNode temp = current.next;
			current.next = prior;
			prior = current;
			current = temp;
		}
		return prior;
	}
}
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号