剑指offer 56-60

56.删除链表中重复结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

这个题最开始的时候本人用的是三指针的方法,pre保留前一个位置,cur表示当前位置,next表示下一个位置,当cur.val==next.val时开始循环找到第一个不重复的点,然后将cur移动到这个位置,实际写起来又臭又长且由于三指针的存在对一些特殊情况很容易搞错或遗漏,看到了newcode大神在github上的代码,恍然大悟,对这种题用递归看起来更简单,更加容易理解,代码也更简洁;
思路如下

方法为public ListNode deleteDuplication(ListNode pHead){}
输入为一个结点,返回的是以这个结点为头结点的链表经过删除重复结点这个操作之后得到的链表的头结点;
OK我们搞懂了这个函数干了件啥事儿,我们就可以直接把这个函数的返回值拿来用,即deleteDuplication(node)返回的是以node为头结点的链表经过删除重复结点这一操作之后得到的头结点,我们先理解这一点,在抽象角度理解它,对递归大有裨益!然后再去实际的,方法体中的具体操作;
1.首先当然还是判断输入是否为空,或者输入是否是单结点,对于这两种情况我们都直接返回它本身即可;
2.由于我们要考察重复结点,所以我们需要一个指针指向的是pHead的下一个结点;
3.下一步,主函数体来了,如果pHead.val==next.val,就一直循环找到第一个和pHead的值不相等的结点,例如1->1->2->3,找到的第一个与1不相等的结点是2,由于1,1我们都要删除的,next此时也在2这位置了,那么怎么样,我们的问题是不是相当于以2这个结点为头结点重新做这个方法?
即返回值应该用deleteDuplication(next)来操作,我们把这个操作记做操作1;
如果不相等呢,OK,那么证明这个pHead这个结点不是重复结点,那么我们只需要确保它后面的结点是不含重复结点的链表即可,上升到递归的宏观角度来看,我们怎么做pHead.next = deleteDuplication(pHead.next)即可,我们把这个操作记做操作2;
其实在实际递归中这两种递归方法都是交叉使用的,好就好在返回的是一个结点,而pHead.next这一操作又可以将递归返回的各结点之间相连接起来;
弄几个具有特点的例子来分析下
1,1,1,1,1,1,1,1这个例子一进来就是pHead.val==next.val直接用操作一,返回的是deleteDuplication(null),即返回null,正好符合
1,2,3,3,4,4,5,首先pHead.next = deleteDuplication(2),然后相当于对2这个结点进行操作,然后2不重复,又2.next = deleteDuplication(3),返回的是deleteDuplication(4),deleteDuplication(4)返回的又是deleteDuplication(5),返回的即5本身,故1->2->5接上了,假设这个题最后一位是4而没有5,也会递归到null,即1->2->null,依然符合;

分析完了,代码如下

public ListNode deleteDuplication(ListNode pHead) {
    if (pHead == null || pHead.next == null)
        return pHead;
    ListNode next = pHead.next;
    if (pHead.val == next.val) {
        while (next != null && pHead.val == next.val)
            next = next.next;
        return deleteDuplication(next);
    } else {
        pHead.next = deleteDuplication(pHead.next);
        return pHead;
    }
}

57.二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。
注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

该题方仿照前面的二叉树和链表的相互转换即可

中序遍历
1.左结点递归
2.do something
3.右结点递归

仿照这个顺序,调整do something的位置即可得到前序和后序的方法
本题中需要注意根节点为给出,需要用next指针来找到根节点
代码如下

public class Solution {
    //初始化一个标志位来表示是否找到了当前结点
    private boolean flag = false;
    //用一个结点res来存储返回的结果
    private TreeLinkNode res = null;
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        //由于存在指向父节点的next指针,所以我们先通过pNode找到根节点
        TreeLinkNode cur = pNode;
        while(cur.next!=null){
            cur = cur.next;
        }
        //找到根节点了之后,这个题的做法就跟之前的二叉树转化为双向链表一模一样
        mid_order(cur,pNode);
        return res;
    }
    
    private  void mid_order(TreeLinkNode node,TreeLinkNode pNode){
        //递归到叶子结点的时候返回
        if(node==null){
            return;
        }
        //中序遍历递归从左结点开始
        mid_order(node.left,pNode);
        //如果flag已经为true了,证明前一个结点已经是给定结点了
        //此时只需把当前结点赋给结点res即可,记得把flag再变为false,不然会造成后面的错误
        if(flag){
            res = node;
            flag = false;
        }
        //找到给定结点了,就把flag变为true,然后接着递归找到下一个结点
        if(node == pNode){
            flag = true;
        }
        mid_order(node.right,pNode);
        
    }
}

你可能感兴趣的:(剑指offer 56-60)