思路:
首先思考,在链表中的处于链首,链中,链尾这三种位置的元素采用的移除方式是否是相同的,首先看链首。
处于链首的元素要移除的话只需要head = head.next即可
处于链中位置的元素则要操作其前一位元素进行删除,若有一个关系为pre.next == cur,其中cur为正在操作的元素,想要删除cur的话则需要pre.next = pre.next.next;
处于链尾的元素与处于链中的元素操作其实是相同的,在此不再赘述。
另外,使用c/c++的伙伴要额外考虑空间的释放问题
思考完三类元素的删除方式后,会发现处于链首的元素删除方式是与其他两者不同的,我们可以选择在代码中加入一个if判断对其进行特殊处理,又或者说,可以用一个更巧妙的办法把链首元素的操作调整为与其他两者一致的操作,那便是加入虚拟头结点dummyHead
加入了虚拟头结点dummyHead之后,dummyHead.next = head;,使得它的下一个节点为头结点,这样操作虚拟头结点dummyHead.next = dummyHead.next.next,便能够实现对于头结点的移除,下面是代码实现
//遇到的问题,在temp = temp.next的时候没有设置为else
//应该用节点的下一位进行检测而非节点本身,不然要另外写一个上节点很麻烦
public static ListNode removeElements(ListNode head, int val) {
//创建一个虚拟头结点dummyHead
ListNode dummyHead = new ListNode();
dummyHead.next = head;
//临时节点存储数据
ListNode temp = dummyHead;
while(temp.next !=null){
if(temp.next.val == val){
ListNode temp2 = temp.next;
temp.next = temp.next.next;
System.out.println(temp2.val);
}
else {
temp = temp.next;
}
}
return dummyHead.next;
}
public static class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
这是个综合考验对链表操作实现的题目,其实整体并没有什么难的地方,但是逻辑要很紧密,不然多个功能合在一起后就会出现bug频出的场面,非常难受(说的就是我),很无奈只能一个个去debug
思路:
添加节点
删除节点
//设计链表节点对象
class ListNode{
public int val;
ListNode next;
public ListNode(){
next = null;
}
public ListNode(int val){
this.val = val;
}
}
//将链表的整体及相关操作另外设置成一个对象
//不能将自身设置为节点,节点要额外设置
class MyLinkedList {
int capacity;//容量
ListNode _dummyHea;//虚拟头结点
public MyLinkedList() {
_dummyHea = new ListNode(0);
capacity =0;
}
public int get(int index) {
if(index<0||index>=capacity){
return -1;
}
ListNode temp = _dummyHea.next;
for(int i=0;i<index;i++){
temp = temp.next;
}
return temp.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);//相当于头部插入
}
public void addAtTail(int val) {
addAtIndex(capacity,val);//相当于尾部插入
}
public void addAtIndex(int index, int val) {
if(index<0||index>capacity){
return;
}
capacity ++;
//使其等于检测节点上一位
ListNode pre = _dummyHea;//其等于虚拟头结点
for(int i=0;i<index;i++){
pre = pre.next;
}
ListNode temp = new ListNode(val);
temp.next = pre.next;
pre.next = temp;
}
public void deleteAtIndex(int index) {
if(index<0||index>=capacity){
return;
}
capacity--;
//使其等于检测节点上一位
ListNode temp = _dummyHea;
if(index ==0){
_dummyHea = _dummyHea.next;
return;
}
for (int i = 0; i < capacity; i++) {
if(index == i){
temp.next = temp.next.next;
break;
}
else{
temp = temp.next;
}
}
}
public void print(){
ListNode temp = _dummyHea;
for (int i = 0; i < capacity; i++) {
System.out.print(temp.next.val+"\t");
temp = temp.next;
}
System.out.println("");
}
}
思路:
第一眼看到这个题目,首先想的是新建一个数组存入链表的数值,随后将数组的数值按照倒序赋值给一个新建立一个链表,最后这个新建立的链表返回。
之后看了卡哥的思路后发现这根本就是没有必要的,只需要在原本的链表上进行操作即可
操作过程如下:
只需要三个变量pre,cur,temp即可完成这个操作,下面是代码实现,十分简洁
public ListNode reverseList(ListNode head) {
if(head == null||head.next==null){
return head;
}
ListNode cur = head;
ListNode pre = null;
ListNode temp;
while(cur != null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
以上为本次训练的三个题目,谢谢观看!