一、移除链表元素
力扣203
对链表进行遍历,删除指定元素的结点。
对于单向链表,删除链表中结点时,指针应位于要删除结点的前一个结点,这样才能对其进行删除操作。删除操作为node.next = node.next.next。应注意用while判断处理连续出现要被删除结点的情况。
时间复杂度: O(n)
/**
* 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;
}
while(head != null && head.val == val){
head = head.next;
}
ListNode current = head;
while(current != null){
while(current.next != null && current.next.val == val){
current.next = current.next.next;
}
current = current.next;
}
// while(current != null){
// 如果将while改为if,则无法处理连续的若干个节点
// if(current.next != null && current.next.val == val){
// current.next = current.next.next;
// }
// current = current.next;
// }
return head;
}
}
二、设计链表
力扣707
1.单链表
class ListNode{ //链表和结点对象
int val; //结点值
ListNode next; //指向下一个结点的指针
ListNode() {}; //初始化一个空链表
ListNode(int val){ //初始化一个结点,结点的值为val
this.val = val;
}
}
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() { //初始化链表
size = 0;
head = new ListNode(0);
}
public int get(int index) {
ListNode cur = head;
if(index < 0 || index >= size){
return -1;
}
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;
}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
ListNode node = new ListNode(val);
node.next = cur.next;
cur.next = node;
size++;
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
ListNode cur = head;
if(index == 0){
head = head.next;
}else{
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.next = cur.next.next;
}
size--;
}
}
2.双链表
class ListNode{
int val; //结点值
ListNode next; //指向下一个结点的指针
ListNode prev; //指向上一个结点的指针
ListNode() {}; //初始化一个空链表
ListNode(int val){ //初始化一个结点,结点的值为val
this.val = val;
}
}
class MyLinkedList {
int size;
ListNode head;
ListNode 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;
if (index == 0){
return head.next.val;
}
//判断是哪一边遍历时间更短
if(index >= size / 2){
//tail开始
cur = tail;
for(int i = 0; i < size-index; i++){
cur = cur.prev;
}
}else{
for(int i = 0; i <= index; i++){
cur = cur.next;
}
}
//System.out.println("get到第" + index + "个元素是" + cur.val);
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);
//System.out.println("在头结点前加的元素是" + val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
//System.out.println("在尾结点后加的元素是" + val);
}
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 node = new ListNode(val);
node.next = cur.next;
cur.next.prev = node;
node.prev = cur;
cur.next = node;
size++;
//System.out.println("在第" + index + "个位置加的元素是" + cur.val);
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
ListNode node = cur.next;
//System.out.println("在第" + index + "个位置删除的元素是" + node.val);
cur.next = cur.next.next;
cur.next.prev = cur;
size--;
}
}
三、反转链表
力扣206
可以原地反转链表而不用申请额外空间。
设置三个结点指针,pre(前一个结点)和cur(当前结点)和node(暂存cur的后一个结点)。先使用node将cur的后一个结点暂存。然后将cur的next指针指向pre,完成指针反转,随后令pre指向cur,cur指向cur的后一个结点(cur=node)。
时间复杂度: O(n)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode node = null;
while(cur != null){
node = cur.next; //标记cur的下一个结点,令其不丢失
cur.next = pre; //指针改为从后向前
pre = cur; //pre后移
cur = node; //cur后移
}
return pre;
}
}