剑指offer思路总结
1、链表
1.1 从尾到头打印链表
题目概述:给出一个链表的表头,从尾到头反过来打印出每个结点的值。
(1)若可以改变链表
思路:把链表反转,在遍历。
(2)不能改变链表
思路:可以借助辅助栈的后进先出;
可以利用递归实现。
1.2 删除链表的结点
题目一大致描述:给定一个单向链表的头结点和一个结点指针,要求在O(1)时间内删除该节点。
思路:因为要求是O(1),所以考虑先复制后结点的值,然后删除。需要注意头结点,尾结点情况。
题目二大致描述:链表有序,删除链表中重复的结点
思路:为了避免头结点可能被删除的情况,引进一个新的头结点,然后使用两个指针pre,cur进行即可。
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null)
return null;
ListNode newHead = new ListNode(-1);
newHead.next = head;
ListNode cur = head; //当前节点
ListNode pre = newHead; //前驱节点
while(cur != null && cur.next != null){
if(cur.val == cur.next.val){ //判断是否相同
int a = cur.val;
while(cur != null && cur.val == a){ //找出不相同的节点
cur = cur.next;
}
pre.next = cur;
// pre = cur; 如果多了这条,会出错,所以需要注意
}else{
pre = cur;
cur = cur.next;
}
}
return newHead.next;
}
}
题目三:去重复元素,但每一个只保留一次。
思路:一次遍历,出现相同就跳一个指针。
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while(current != null && current.next != null){
if(current.val == current.next.val){
current.next = current.next.next;
}else {
current = current.next;
}
}
return head;
}
}
1.3 链表中的倒数第k个结点
题目大致概述:给出一个链表,输出链表中倒数第k个结点。
思路:双指针,一个先走k步,然后同时起步。
1.4 链表中环的入口
题目概述:一个链表中包含环,找出环的入口。
思路: 双指针,一个每次走一步,一个每次走两步,当相遇时,第二个指针刚好比第一个走多了一个环大小的距离,然后一个指针从头节点重新开始走,相遇时的节点就是环的入口。
1.5 反转链表
题目概述:给定一个链表,反转该链表。
思路:双指法。一个指针记录为反转的链表头节点,一个是反转了的链表的头节点。
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
1.6 合并两个排序的链表
题目概述:给定俩个递增的链表,合并两个链表,使其依旧是递增排序。
思路:递归法。
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null)
return l2;
if(l2 == null)
return l1;
ListNode head = null;
if(l1.val > l2.val){
head = l2;
head.next = mergeTwoLists(l1 , l2.next);
}else {
head = l1;
head.next = mergeTwoLists(l1.next , l2);
}
return head;
}