内容概要:
题目:
删除链表中等于给定的val的所有元素。
示例:
给定:1—>2—>6—>3—>4—>5—>6,val=6
返回:1—>2—>3—>4—>5
给定的ListNode类
public class ListNode { public int val; public ListNode next; public ListNode(int x) { val = x; } }
问题分析:
首先,判断链表是否为空(head!=null)为空则返回head,不为空执行下面删除操作
处理特殊位置,链表头部的删除工作:如果head是val值(head.val=val)
ListNode delNode=head; head=head.next; delNode.next=null;
然后删除中间位置的方法:
定义prev为要删除节点的前一个节点
ListNode prev=head;
prev.next下一个节点不为空则且prve.next.val==val则执行删除操作
ListNode delNode=prev.next;//定义要删除的节点 prev.next=delNode.next; delNode.next=null;
否则,prev=prev.next;继续往下找
class Solution { public ListNode removeElements(ListNode head, int val) { //1假设head节点的val等于给定的val //1解决头结点的删除 while (head != null && head.val == val) { //定义要删除的那个节点 ListNode delNode = head; head = head.next; delNode.next = null; } //如果头结点为空 if (head == null) return null; //2解决中间部分的删 ListNode prev = head;//头结点为下一个节点的前一个节点 while (prev.next != null) {//下一个节点不为空 if (prev.val == val) {///中间部分的某一个节点的val等于给定val ListNode delNode = prev.next; prev.next = delNode.next; delNode.next = null; } else {//prev往下找 prev = prev.next; } } return head; } }
在链表的头部设置一个虚拟头结点,则除了头部删除和中间删除都是同一个操作
class Solution2 { public ListNode removeElements(ListNode head, int val) { ListNode dummyhead = new ListNode(-1);//设置虚拟节点,值任意 dummyhead.next = head;//虚拟节点成头结点 //解决头结点和中间部分的删 ListNode prev = dummyhead;//头结点为下一个节点的前一个节点 while (prev.next != null) {//下一个节点不为空 if (prev.next.val == val) {///中间部分的某一个节点的val等于给定val // ListNode delNode = prev.next; // prev.next = delNode.next; // delNode.next = null; prev.next = prev.next.next;//和上面三句等效 } else {//prev往下找 prev = prev.next; } } return dummyhead.next;//虚拟头结点不展示 }}
在给定的ListNode类中,写一个带参构造函数,参数传进来一个整形数组,转成链表
public class ListNode { public int val; public ListNode next; public ListNode(int x) { val = x; } //链表节点的构造函数 //使用arr为参数。创建一个链表。当前的ListNode为链表的头结点 public ListNode(int[] arr) { if (arr == null || arr.length == 0) throw new IllegalArgumentException("arr cannot be empt"); this.val = arr[0]; ListNode cur = this;//this用来保存cur的状态 //里面记录的所以cur的状态1->NUll /1->2->NULL/1->2->3-NULL.... for (int i = 1; i < arr.length; i++) { cur.next = new ListNode(arr[i]);//每次传入新的参数生成新的对象,赋值给cur.next cur = cur.next;//将cur.next传给cur作为新的cur的位置,传递 } } @Override public String toString() { StringBuilder res = new StringBuilder(); ListNode cur = this;//this通过上面的方法村里 while (cur != null) { res.append(cur.val + "->"); cur = cur.next; } res.append("NULL"); return res.toString(); } }
在Solution中实现测试
public static void main (String[] args){ int[] nums={1,2,3,6,4,5,6}; //利用带参构造函数将数组变成新的链表 ListNode node=new ListNode(nums); System.out.println(node); ListNode newNode=new Solution().removeElements(node,6); System.out.println(newNode); }
结果:
1->2->3->6->4->5->6->NULL 1->2->3->4->5->NULL
递归:本质上,将原来的问题,转化为更小的同一问题
/** * 采用递归的方式来计算数组的和 */ public class Sum { public static int sum(int[] arr) { return sum(arr, 0);//递归的调用,从0到n-1的和 } //真正的递归 //计算arr[l,n)这个区间内所有数字的和 protected static int sum(int[] arr, int l) { if (l == arr.length) return 0; //解决的问题规模变小了一层一层的调用(计算【l+1,n)的和...计算[n-1,n)的和) return arr[l] + sum(arr, l + 1); }}
测试函数: 结果36
public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5, 6, 7, 8}; System.out.println(sum(arr)); }
用递归算法的两个步骤:
用递归的算法解决删除链表元素中为e的值
/** * 使用递归解决删除链表中为e的元素 */ class Solution2 { public ListNode removeElements(ListNode head, int val) { //第一步:解决最基本的问题 if (head == null) return null; head.next = removeElements(head.next, val); return head.val == val ? head.next : head; } public static void main(String[] args) { int[] nums = {1, 2, 3, 6, 4, 5, 6}; //利用带参构造函数将数组变成新的链表 ListNode node = new ListNode(nums); System.out.println(node); ListNode newNode = new Solution2().removeElements(node, 6); System.out.println(newNode); } }
如果不解决函数的基本问题(最后那一层,head==null),递归将永远进行下去,直到占满系统栈的空间。
使用打印输出的方式来理解从链表移除val元素的值的运行过程
/** * 使用打印输出的方式来输出链表移除元素val的值的运行过程 */ class Solution2 { public ListNode removeElements(ListNode head, int val, int depth) { String depthString = generateDepthString(depth); System.out.print(depthString); System.out.println("Call:remove " + val + " in " + head); //第一步:解决最基本的问题 if (head == null) { System.out.print(depthString); System.out.println("Return:remove " + head); return null; } ListNode res = removeElements(head.next, val, depth + 1); System.out.print(depthString); System.out.println("After:remove " + val + " in " + res); ListNode ret;//暂存 if (head.val == val) ret = res; else head.next = res; ret = head; System.out.print(depthString); System.out.println("Return: " + ret); return ret; } private String generateDepthString(int depth) { StringBuilder res = new StringBuilder(); for (int i = 0; i < depth; i++) { res.append("-|"); } return res.toString(); } public static void main(String[] args) { int[] nums = {1, 2, 3, 6, 4, 5, 6}; //利用带参构造函数将数组变成新的链表 ListNode node = new ListNode(nums); System.out.println(node); ListNode newNode = new Solution2().removeElements(node, 6, 0); System.out.println(newNode); } }
输出结果:
1->2->3->6->4->5->6->NULL Call:remove 6 in 1->2->3->6->4->5->6->NULL -|Call:remove 6 in 2->3->6->4->5->6->NULL -|-|Call:remove 6 in 3->6->4->5->6->NULL -|-|-|Call:remove 6 in 6->4->5->6->NULL -|-|-|-|Call:remove 6 in 4->5->6->NULL -|-|-|-|-|Call:remove 6 in 5->6->NULL -|-|-|-|-|-|Call:remove 6 in 6->NULL -|-|-|-|-|-|-|Call:remove 6 in null -|-|-|-|-|-|-|Return:remove null -|-|-|-|-|-|After:remove 6 in null -|-|-|-|-|-|Return: 6->NULL -|-|-|-|-|After:remove 6 in 6->NULL -|-|-|-|-|Return: 5->6->NULL -|-|-|-|After:remove 6 in 5->6->NULL -|-|-|-|Return: 4->5->6->NULL -|-|-|After:remove 6 in 4->5->6->NULL -|-|-|Return: 6->4->5->6->NULL -|-|After:remove 6 in 6->4->5->6->NULL -|-|Return: 3->6->4->5->6->NULL -|After:remove 6 in 3->6->4->5->6->NULL -|Return: 2->3->6->4->5->6->NULL After:remove 6 in 2->3->6->4->5->6->NULL Return: 1->2->3->6->4->5->6->NULL 1->2->3->6->4->5->6->NULL