Day4
移除列表元素
link:203. 移除链表元素 - 力扣(LeetCode)
首先单向链表是有一个数据域和指针域且在内存中不连续.
链表的查找需要从头往后一个个查找【时间复杂度为O(n)】,但是数组查找只需要访问对应元素下标即可【时间复杂度为O(1)】.
查找频繁:数组是更好的选择,因为通过索引访问的时间复杂度是 O(1),链表则需要遍历.
插入/删除频繁:链表更适合,因为它可以高效地插入和删除元素,时间复杂度为 O(1)O(1)O(1)(假设已找到插入或删除位置)。相反,数组在插入和删除时需要移动大量元素,时间复杂度为 O(n).
思路分析
看到题目最第一反应就是常规解法,遍历链表找到target直接进行删除操作.【目标是头节点和不是头节点两种情况】(其实还是想有更优雅的解法 不用单独处理移除头节点的情况)
直接删除
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null){
return null;
}
ListNode cur = head.next;
ListNode prev = head;
while(cur != null){
if(cur.val == val){
prev.next = cur.next;
cur = cur.next;
}
else{
prev = cur;
cur = cur.next;
}
}
if(head.val == val){
head = head.next;
}
return head;
}
}
虚拟头节点
/**
* Definition for singly-linked list.
* public 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 Solution {
public ListNode removeElements(ListNode head, int val) {
//只有头节点
if(head == null) {
return head;
}
//创建虚拟头节点 不用再删除头节点
ListNode dummyNode = new ListNode(-1,head);
ListNode cur = dummyNode;
ListNode prev = head;
while(prev != null) {
if(prev.val == val) {
cur.next = prev.next;
}else {
cur = prev;
}
prev = prev.next;
}
return dummyNode.next;
}
}
设计链表
综合练习链表五大操作的好题目!
1.获取链表的index下标节点数值.
2.在链表最前面插入节点.
3.在链表最后插入节点.
4.在链表第index个节点前插入节点.
5.删除链表第index个节点.
思路分析
先从链表需要的元素入手,head,tail,size.
考虑虚拟头节点.【优先考虑特殊情况】
个人觉得对于单链表更容易操作.(好吧其实就是一个懒蛋😂)
单链表
class ListNode {
//定义需要的结构
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
}
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
int size = 0;
head = new ListNode(0);
}
public int get(int index) {
//如果index不在范围返回-1
if(index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
//虚拟头节点的存在 使得返回index+1个节点"=""
for(int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}
//如果index等于0 新插入的节点就为头节点
public void addAtHead(int val) {
addAtIndex(0,val);
}
//如果index等于链表长度 此时插入的新节点为尾节点
public void addAtTail(int val) {
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
//如果index大于链表长度 返回null
if(index > size) {
return;
}
if(index < 0) {
index = 0;
}
size++;
ListNode prev = head;
//找到要插入节点的前驱
for(int i = 0; i < index ;i++) {
prev = prev.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = prev.next;
prev.next = toAdd;
}
public void deleteAtIndex(int index) {
//同样的判断逻辑
if(index < 0 || index >= size) {
return;
}
size--;
ListNode prev = head;
for(int i = 0; i < index; i++) {
prev = prev.next;
}
prev.next = prev.next.next;
}
}
双链表
用双链表操作时需要注意指针操作的逻辑.
head.next = tail;
tail.next = head;
index < (size - 1) / 2
判断用来决定是从头节点还是尾节点进行遍历,这样做是为了提高查找效率
class MyLinkedList {
class ListNode {
int val;
ListNode next,prev;
ListNode(int x) {val = x;}
}
int size;
ListNode head,tail;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.prev = head;
}
public int get(int index) {
if(index < 0 || index >= size){return -1;}
ListNode cur = head;
// 通过判断 index < (size - 1) / 2 来决定是从头结点还是尾节点遍历,提高效率
if(index < (size - 1) / 2){
for(int i = 0; i <= index; i++){
cur = cur.next;
}
}else{
cur = tail;
for(int i = 0; i <= size - index - 1; i++){
cur = cur.prev;
}
}
return cur.val;
}
public void addAtHead(int val) {
ListNode cur = head;
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next.prev = newNode;
cur.next = newNode;
newNode.prev = cur;
size++;
}
public void addAtTail(int val) {
ListNode cur = tail;
ListNode newNode = new ListNode(val);
newNode.next = tail;
newNode.prev = cur.prev;
cur.prev.next = newNode;
cur.prev = newNode;
size++;
}
public void addAtIndex(int index, int val) {
if(index > size){return;}
if(index < 0){index = 0;}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next.prev = newNode;
newNode.prev = cur;
cur.next = newNode;
size++;
}
public void deleteAtIndex(int index) {
if(index >= size || index < 0){return;}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.next.next.prev = cur;
cur.next = cur.next.next;
size--;
}
}