目录
四、链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)
六、链表分割_牛客题霸_牛客网 (nowcoder.com)
七、链表的回文结构_牛客题霸_牛客网 (nowcoder.com)
十、 142. 环形链表 II - 力扣(LeetCode)
我们遍历一次链表来解决这个问题。首先我们定义两个节点,ListNode cur = head.next;
ListNode prve = head;在while(cur != null){ } 循环里判断是否等于要删除的元素,当等于要删除的元素时:
当不等于要删除的元素时:
最后在单独判断一下头结点:
- if(head.val == key){
- head = head.next;
- }
完整代码展示:
- public ListNode removeElements(ListNode head, int key) {
- if (head == null){
- return null;
- }
- ListNode cur = head.next;
- ListNode prve = head;
- while (cur != null){
- if(cur.val == key){
- prve.next = cur.next;
- cur = cur.next;
- }else{
- prve = cur;
- cur = cur.next;
- }
- }
- if(head.val == key){
- head = head.next;
- }
- return head;
- }
我们可以先定义一个head.next节点,然后再将头结点置为null:
- ListNode cur = head.next;
- head.next = null;
然后我们在循环里面需要记住cur.next,所以定义一个curNext = cur.next:
然后我们运用头插法,将cur插入到head前面,再移动head和cur和curNext:
当然在一开始需要判断head和head.next是否为空,完整代码如下:
- public ListNode reverseList(ListNode head) {
- if(head == null){
- return null;
- }
- if(head.next == null){
- return head;
- }
- ListNode cur = head.next;
- head.next = null;
- while (cur != null){
- ListNode curNext = cur.next;
- cur.next = head;
- head = cur;
- cur = curNext;
- }
- return head;
- }
这个题在遍历一次链表的情况下,我们可以使用快慢指针:
即定义一个fast指针一次走两步,slow指针一次走一步,再遍历整个链表,当fast指针指向空时,slow指针便指向的是链表的中间位置。也会有两种情况,链表的长度为奇数和偶数时。
奇数时:
偶数时:
完整代码:
- public ListNode middleNode(ListNode head) {
- if (head == null){
- return null;
- }
- ListNode slow = head;
- ListNode fast = head;
- while (fast != null && fast.next != null){
- fast = fast.next.next;
- slow = slow.next;
- }
- return slow;
- }
注:fast != null && fast.next != null 这两个的顺序不能调换,否则会空指针异常(先判断fast.next 是否为空时,fast已经是空了).
这道题我们还是运用了快慢指针的思想:
定义fast和slow指针,先让fast指针走k-1步,再两个指针一起走,直到fast.next为空。当然首先要判断k值是否合理,可以在fast指针走k-1步时实现;
代码如下:
- public ListNode FindKthToTail(ListNode head, int k){
- if (head == null || k <= 0){
- return null;
- }
- ListNode slow = head;
- ListNode fast = head;
- while (k-1 != 0){
- fast = fast.next;
- if (fast == null){ //判断k是否合理
- return null;
- }
- k--;
- }
- while (fast.next != null){
- fast = fast.next;
- slow = slow.next;
- }
- return slow;
- }
我们可以先实例化一个虚拟节点,然后在while(head1 != null && head2 != null){} 的时候,比较一下head1.val和head2.val的大小,将小的节点放到虚拟节点后面,,最后遍历完一个链表时,将剩下的链表整合到一起.
完整代码:
- public ListNode mergeTwoLists(ListNode head1, ListNode head2) {
- ListNode newHead = new ListNode(-1);//虚拟节点
- ListNode tmp = newHead;
- while (head1 != null && head2 != null) {
- if (head1.val < head2.val) {
- tmp.next = head1;
- head1 = head1.next;
- tmp = tmp.next;
- } else {
- tmp.next = head2;
- head2 = head2.next;
- tmp = tmp.next;
- }
- }
- if (head1 != null) {
- tmp.next = head1;
- }
- if (head2 != null) {
- tmp.next = head2;
- }
- return newHead.next;
- }
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针:
下面我们来具体的实现代码:
- public ListNode partition(ListNode head, int x) {
- ListNode bs = null;
- ListNode be = null;
- ListNode as = null;
- ListNode ae = null;
- ListNode cur = head;
- while (cur != null){
- if(cur.val < x){
- //插入到第一个段【尾插法】
- if(bs == null){
- //这是第一次插入元素
- bs = cur;
- be = cur;
- }else{
- be.next = cur;
- be = be.next;
- }
- }else {
- //插入到第二个段【尾插法】
- if (as == null) {
- //这是第一次插入元素
- as = cur;
- ae = cur;
- } else {
- ae.next = cur;
- ae = ae.next;
- }
- }
- cur = cur.next;
- }
- //当没有小于x的结点时,bs就是null
- if(bs == null){
- return as;
- }
- //将be和as串起来
- be.next = as;
- //ae.next不一定null,需要手动将其置空
- if(as != null){
- ae.next = null;
- }
- return bs;
- }
这道题的思路如下:
- public boolean chkPalindrome(ListNode head) {
- if(head == null){
- return true;
- }
- ListNode fast = head;
- ListNode slow = head;
- //通过快慢指针找到中间位置,
- while (fast != null && fast.next != null){
- fast = fast.next.next;
- slow = slow.next;
- }
- //逆置后半段的链表
- ListNode cur = slow.next;
- while (cur != null){
- ListNode curNext = cur.next;
- cur.next = slow;
- slow = cur;
- cur = curNext;
- }
- //两头开始遍历比较val值是否相同
- while (head != slow){
- if (head.val != slow.val){
- return false;
- }
- if (head.next == slow){//两边相遇了
- return true;
- }
- head = head.next;
- slow = slow.next;
- }
- return true;
- }
思路:
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- //分别求出两个链表的长度
- int lenA = 0;
- int lenB = 0;
- ListNode p1 = headA;//代表永远指向长的链表
- ListNode p2 = headB;//代表永远指向短的链表
- while(p1 != null){
- lenA++;
- p1 = p1.next;
- }
- while (p2 != null){
- lenB++;
- p2 = p2.next;
- }
- p1 = headA;
- p2 = headB;
- //求出差值
- int len = lenA - lenB;
- if(len < 0){
- p1 = headB;//代表永远指向长的链表
- p2 = headA;//代表永远指向短的链表
- len = lenB - lenA;//len一定是一个正数
- }
- //让长的链表走了差值步
- while (len != 0){
- p1 = p1.next;
- len--;
- }
- //找到相同的点,直到相遇
- while(p1 != p2){
- p1 = p1.next;
- p2 = p2.next;
- }
- return p1;
- }
思路:
- public boolean hasCycle(ListNode head) {
- ListNode slow = head;
- ListNode fast = head;
- while (fast != null && fast.next != null){
- fast = fast.next.next;
- slow = slow.next;
- if(fast == slow){
- return true;
- }
- }
- return false;
- }
思路:
- public ListNode detectCycle(ListNode head) {
- ListNode slow = head;
- ListNode fast = head;
- while (fast != null && fast.next != null){
- fast = fast.next.next;
- slow = slow.next;
- if(fast == slow){
- break;
- }
- }
- if (fast == null || fast.next == null){
- return null;
- }
- slow = head;
- while (slow != fast){
- slow = slow.next;
- fast = fast.next;
- }
- return fast;
- }