代码随想录算法训练营第三天|203.移除元素|707.设计链表|206.反转链表

本文详细介绍了如何在链表中移除元素,包括迭代和递归两种方法,并提供了Java实现。同时,讨论了设计链表的单链表和双链表结构,以及如何进行添加、删除和获取元素的操作。最后,阐述了链表反转的迭代和递归解法。
摘要由CSDN通过智能技术生成

LeetCode203.移除元素

迭代

        基本思路:从头到尾一个一个遍历链表节点,判断是否是需要移除的数,如果是,就把当前节点的next指向下个节点的next(也就是指向下下个节点,把中间这个节点孤立),就实现了删除。需要注意,当给定链表的第一个节点就需要删除的时候,容易出现判断上的错误(第一个没删到,踩过这个坑),所以可以使用一个虚拟节点(dummyNode)接到给定链表头节点的前面,dummyNode.next = head,然后使用dummyNode作为头节点进行遍历判断就可以了。

Java代码如下:

public ListNode removeElements(ListNode head, int val) {
        ListNode dummyNode = new ListNode(0);
    	dummyNode.next = head;
    	ListNode index = dummyNode;
    	while(index.next != null) 
    	{
    		if(index.next.val == val) 
    		{
    			index.next = index.next.next;
    		}else 
    		{
    			index = index.next;
    		}
    	}
    	return dummyNode.next;
    } 

时间复杂度:O(n)

空间复杂度:O(1)

递归

         基本思路:如果当前节点不为空,就继续向下递归(调用自己函数,传入当前节点的下一个节点,继续进行判断),当前节点为空了,说明到了链表的结尾,把当前节点返回给上一个节点,判断这个节点的值是否等于给的val,如果相等,返回这个节点的next给上一个节点,如果不相等就返回这个节点给上一个节点。相当于是一个从后到前的过程。

Java代码如下:

public ListNode removeElements_day03_1(ListNode head, int val) {
    	if(head == null) 
    	{
    		return head;
    	}
    	
    	head.next = removeElements_day03_1(head.next,val);
    	return head.val == val ? head.next : head;
    }

 LeetCode707.设计链表

单链表

        模拟链表操作,没有什么难点,注意特殊输入的判断就行。

Java代码如下:

class ListNode {
	int val;
	ListNode next;

	ListNode() {
	}

	ListNode(int val) {
		this.val = val;
	}

	ListNode(int val, ListNode next) {
		this.val = val;
		this.next = next;
	}
}
class MyLinkedList {
    	int size;
    	ListNode head;
        public MyLinkedList() {
        	size = 0;
        	head = new ListNode(0);
        }
        
        public int get(int index) {
        	if(index < 0 || index >= size) 
        	{
        		return -1;
        	}
        	
        	ListNode currentNode = head;
        	for(int i = 0 ; i <= index ; i++) 
        	{
        		currentNode = currentNode.next;
        	}
        	return currentNode.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;
        	}
        	size++;
        	ListNode pred = head;
        	for(int i = 0; i < index ; i++) 
        	{
        		pred = pred.next;
        	}
        	ListNode toAdd = new ListNode(val);
        	toAdd.next = pred.next;
        	pred.next = toAdd;
        }

 双链表

  注意事项:在初始化的时候需要对两个节点进行连接,不然回出现空指针的异常,主要是要注意添加节点和删除节点的时候新增节点和删除节点与之对应的前后节点之间的指向关系,要捋清楚。

Java代码如下:

class ListNode_d{
        int val;
        ListNode_d next,prev;
        ListNode_d() {};
        ListNode_d(int val){
            this.val = val;
        }
    }
    
    class MyLinkedList_1 {
    	
    	int size;
    	ListNode_d head;
    	ListNode_d tail;
        public MyLinkedList_1() {
        	this.size = 0;
        	this.head = new ListNode_d(0);
        	this.tail = new ListNode_d(0);
        	head.next = tail;
        	tail.prev = head;
        }
        
        public int get(int index) {
        	if(index < 0 || index >= size) 
        	{
        		return -1;
        	}
        	
        	ListNode_d cur = this.head;
        	if(index >= size / 2) 
        	{
        		cur = tail;
        		for(int i = 0;i < size - index;i++) 
        		{
        			cur = cur.prev;
        		}
        	}else 
        	{
        		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;
        	}
        	size++;
        	ListNode_d pre = this.head;
        	for(int i = 0; i < index;i++) 
        	{
        		pre = pre.next;
        	}
        	ListNode_d newNode = new ListNode_d(val);
        	newNode.next = pre.next;
        	pre.next.prev = newNode;
        	newNode.prev = pre;
        	pre.next = newNode;
        }
        
        public void deleteAtIndex(int index) {
        	if(index < 0 || index >= size) 
        	{
        		return;
        	}
        	size--;
        	ListNode_d pre = this.head;
        	for(int i = 0 ; i < index ; i++) 
        	{
        		pre = pre.next;
        	}
        	pre.next.next.prev = pre;
        	pre.next = pre.next.next;
        }
    }

LeetCode 207.反转链表

迭代

       基本思路:new两个节点,一个pre(指向当前节点的前一个节点,初始化为null),一个curr(指向当前节点,初始化为head),写一个while循环,循环的成立条件为 curr != null,也就是遍历整个链表,单次循环的流程如下:

        (1)new一个新的节点next,用于指向curr的next,因为后续会对curr指向的节点进行修改,所以需要先保存好。

        (2)把curr.next 指向 pre,也就是反向操作,当前节点的next指向前一个节点。

        (3)然后pre和cur都进行后移,pre = curr,curr = next。这样一次循环就结束了

当while结束,直接返回pre节点即可(最后一次循环结束之后,curr是指向null的,pre才是最后一个节点)。

Java代码如下:

    public ListNode reverseList(ListNode head) {
    	ListNode pre = null;
    	ListNode curr = head;
    	while(curr != null) 
    	{
    		ListNode next = curr.next;
    		curr.next = pre;
    		pre = curr;
    		curr = next;
    	}
    	
    	return pre;
    }

 

递归 

        基本思路:进入方法第一件事就是先判断,传入的节点是否为链表的子最后一个节点,如果是,返回当前节点,如果不是,继续调用自身节点,将head.next传入(相当于是一个入栈的过程),直到遍历到了链表的最后一个节点,当前节点返回了,第一个函数出栈,将值给了第二个函数,这个函数拿到了这个值之后就开始进行反向的操作,具体操作如下:

(1)new一个节点cur接收之前反转过后的链表。

(2)当前head指向的位置是之前反转过后的链表的前一个位置,相当于是迭代方法中的pre节点,因为每次递归传入的参数都是head.next。直接进行反转,head.next.next = head,反转完成之后要记得将head.next置为空,如果不置为空,到最后会出现环。

(3)将新的反转之后的链表return给下一个函数。

Java代码如下:

public ListNode reverseList(ListNode head) {
    	if(head == null || head.next == null) 
    	{
    		return head;
    	}
    	ListNode cur = reverseList(head.next);
    	head.next.next = head;
    	head.next = null;
    	
    	return cur;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值