代码随想录算法训练营第三天|203.移除链表元素、 707.设计链表、206.反转链表
关于链表
单链表 结点的类定义
class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
203 移除链表元素
解题思路
- 遍历知道头节点不等于这个val
- 如果头节点为空了,则返回 head
- 设置一个 dummy 指向 头节点,维护想要的链表 (dummyNode 虚拟结点 dummy 假的)
- 用 cur 来遍历结点,将需要的结点链接到 dummy 上,dummy也会动,当需要的时候动,cur是无论什么时候都动
- 最后返回head 链表就对啦
代码
public class ListNodeRemoveElements3 {
public static void main(String[] args) {
// ListNode node1 = new ListNode(1);
// ListNode node2 = new ListNode(2);
// ListNode node3 = new ListNode(6);
// ListNode node4 = new ListNode(3);
// ListNode node5 = new ListNode(4);
// ListNode node6 = new ListNode(5);
// ListNode node7 = new ListNode(6);
// node1.next = node2;
// node2.next = node3;
// node3.next = node4;
// node4.next = node5;
// node5.next = node6;
// node6.next = node7;
// System.out.println(node1);
// System.out.println(removeElements(node1, 6));
// System.out.println(node1);
ListNode node1 = new ListNode(7);
ListNode node2 = new ListNode(7);
ListNode node3 = new ListNode(7);
ListNode node4 = new ListNode(7);
ListNode node5 = new ListNode(7);
ListNode node6 = new ListNode(7);
ListNode node7 = new ListNode(7);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
System.out.println(node1);
System.out.println(removeElements(node1, 7));
System.out.println(node1);
}
// 我理解的不污染结点: 链表只做正确的事,在里面移动的结点,获得的整个链表是符合最终结果的 可以设置为 pre(虚拟结点)
// 我理解的temp结点: 负责帮不污染结点完成正确事的结点,可以先探索下一个结点 可以设置为 cur(当前结点)
// 链表 1 2 6 3 4 5 6
// new pre -> 当头节点
// pre-0 -> head-1
// cur = head
// if cur != null
// if cur.val != var
// cur = cur.next // 当不等于的时候 这里思路错了,应该让pre和cur一起指向下一个结点 pre.next = cur.next 然后让 cur = cur.next
// 相当于 cur 一直是一个temp 而pre是个不污染的链表, 而我这里对没有被污染的结点没有做任何改变
// ---
// if cur.val == var // 这里思路对了
// pre.next = cur.next
// cur = cur.next
// pre = pre.next // 这里思路错了,一样的原因,pre是一直移动的,head才是唯一不动的
// 最后错的思路,如果head不为null以及next都是为同一个值,则会返回一个和以前一样的链表,边界条件没考虑好
// 然后再判断head是否为空
static ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val) {
head = head.next;
}
if (head == null) return head;
ListNode pre = new ListNode(-1, head);
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return head;
}
}
707 设计链表
解题思路
其实没有完全的解决处理问题
我总结几个难点
- 如何通过index 遍历链表 该返回什么样的值
- 如何操作链表,怎么删除结点,众所周知链表的删除操作是O(1)
- 最后就是应该总结一下链表的操作,多写就能随机应变了
代码
package Day3;
public class GPTMyLinkedList {
// 唯一头结点
ListNode head;
public GPTMyLinkedList() {
head = null;
}
public int get(int index) {
ListNode temp = head;
for (int i = 0; i < index; i++) {
// temp为空 则返回找不到链表
if (temp == null) return -1;
temp = temp.next;
}
// 当循环结束,temp为空 则值不存在
if (temp == null) {
return -1;
} else
return temp.val;
}
public void addAtHead(int val) {
// 当头节点不存在,new一个新的
if (head == null) {
head = new ListNode(val, null);
return;
}
// 头节点存在,则把头节点当新头节点的next
head = new ListNode(val, head);
}
public void addAtTail(int val) {
if (head == null) {
head = new ListNode(val);
return;
}
ListNode newNode = new ListNode(val);
ListNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
public void addAtIndex(int index, int val) {
if (index == 0) {
addAtHead(val);
return;
}
ListNode newNode = new ListNode(val);
ListNode temp = head;
for (int i = 0; i < index - 1; i++) {
if (temp == null)
return;
temp = temp.next;
}
if (temp != null) {
newNode.next = temp.next;
temp.next = newNode;
}
}
public void deleteAtIndex(int index) {
if (index == 0) {
if (head != null) head = head.next;
return;
}
ListNode temp = head;
for (int i = 0; i < index - 1; i++) {
if (temp == null)
return;
temp = temp.next;
}
if (temp != null && temp.next != null) {
temp.next = temp.next.next;
}
}
}
206 反转链表
设计思路
- 遍历旧链表,获得最后一个结点
- 将结点加到新链表
- 删除该就链表最后一个结点
- 当就链表的head为null时,结束遍历
看起来这就是一个 笨办法 ……
不过我这个有设计思路,可以拆分成很多小题目
实现代码
/**
* 只适合 维护一个从零开始的空链表
*/
class NewLinkedList {
ListNode head;
ListNode tail;
// 构造函数
NewLinkedList() {
this.head = this.tail = null;
}
// 向链表尾部添加节点的函数
void addNode(ListNode node) {
// 如果链表为空,可以直接插入新节点
if (head == null) {
head = tail = node;
}
// 否则,向尾部插入新节点,并更新tail
else {
tail.next = node;
tail = node;
}
}
}
public class LinkedListReverse {
public static void main(String[] args) {
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(6);
ListNode node7 = new ListNode(7);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
System.out.println(node1);
ListNode reverseNode = solute(node1);
System.out.println(reverseNode);
System.out.println(node1);
}
static ListNode solute(ListNode head) {
NewLinkedList newLinkedList = new NewLinkedList();
while (head != null){
newLinkedList.addNode(lastNode(head));
head = removeLastNode(head);
}
return newLinkedList.head;
}
// 获得链表的最后一位
static ListNode lastNode(ListNode head) {
if (head == null) return head;
ListNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
return temp;
}
// 删除链表的最后一位
static ListNode removeLastNode(ListNode head) {
// 如果链表为空或者只有一个节点
if (head == null || head.next == null) {
return null;
}
ListNode temp = head;
// 找到倒数第二个节点
while (temp.next.next != null) {
temp = temp.next;
}
// 把倒数第二个节点的next设为null,也就是删除了最后一个节点
temp.next = null;
return head;
}
}