zoukankan      html  css  js  c++  java
  • 剑指OFFER 删除链表中重复的结点

    剑指OFFER 删除链表中重复的结点

    题目描述:

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

    分析一下题目,关键点 1.已排序的链表 2.删除重复的结点

    一种比较次的解法

    一开始想不出来,实在没办法了就只能新建一个链表来存储结果,虽然通过了,但是在工作中处理这样的问题时候千万不要在函数里使用malloc,能不用就不用(容易内存泄露)

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        map<int,int> m;
        ListNode* deleteDuplication(ListNode* pHead)
        {
            if(pHead == NULL)return NULL;
            ListNode* node =  pHead;
            ListNode* new_head = NULL;
            while(node != NULL)
            {
                m[node->val]++;
                node = node->next;
            }
    
    
            ListNode* last_node = NULL;
            auto it = m.begin();
            while(it != m.end())
            {
                //把节点添加到新的list当中
                if(it->second == 1)
                {
                    if(new_head == NULL)
                    {
                        new_head = (ListNode*)malloc(sizeof(ListNode));
                        new_head->val = it->first;
                        new_head->next = NULL;
                        last_node = new_head;
                    }else{
                        ListNode* node;
                        node = (ListNode*)malloc(sizeof(ListNode));
                        node->val = it->first;
                        node->next = NULL;
                        last_node->next = node;
                        last_node = node;
                    }
                }
                it++;
            }
    
            return new_head;
        }
    };
    

    还行的解法

    先遍历一遍链表,用map标记需要删除的结点.

    然后再遍历一遍,把要删的结点删除掉,思路比较清晰.

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        map<int,int> m;
        ListNode* deleteDuplication(ListNode* pHead)
        {
            if(pHead == NULL)return NULL;//如果没有结点
            ListNode* node = pHead;
            while(node != NULL)
            {
                m[node->val]++;
                node = node->next;
            }
    
            node = pHead;
            ListNode* last_node = pHead;
            while(node != NULL)
            {
                if(m[node->val]>1)
                {
                    //如果是头结点需要分别对待,因为此时状态中last_node是无效的
                    if(node == pHead)
                    {
                        pHead = pHead->next;
                        node = pHead;
                    }else{
                        last_node->next = node->next;
                        node = last_node->next;
                    }
                    continue;
                }
                //状态转移
                last_node = node;
                node = node->next;
            }
    
            return pHead;
        }
    };
    

    反思:

    没有用到题目中已排序的条件.上面的解法拓宽了题目要求的范围.效率上会有些损失.

    那么,有没有更好的解法?

    应该是有的,通过仅仅一次遍历就可以删除掉重复的元素,但是需要记录前面结点,而且条件判断十分复杂,按着这种思路写了几遍代码,无奈总是有特殊情况没包含进去,放弃了.

    代码先贴这

    ListNode* deleteDuplication(ListNode* pHead)
    {
        if(pHead == NULL)return NULL;//如果没有结点
        if(pHead->next == NULL)return pHead;//如果只有一个结点
        if(pHead->next->next == NULL )//如果只有两个结点
        {
            if(pHead->val == pHead->next->val){
                return NULL;
            }else{
                return pHead;
            }
        }
    
        //如果进入到这里,说明至少有三个结点存在
        //上上个结点,初始化时为头结点(第一个结点)
        ListNode* last_last_node = pHead;
        //上一个节点,初始化时为第二个结点
        ListNode* last_node = pHead->next;
        //当前结点,初始化时为第三个结点
        ListNode* node = pHead->next->next;
    
        while(last_node != NULL && node != NULL)//这里以防万一判断两次
        {
            if(last_node->val == node->val)//出现重复结点,那么last_last_node后面的全部删掉
            {
                //这里last_last_node的值不等于last_node/node的值
                //而last_node的值等于node的值
                ListNode* t_node = last_node;//last_node这里是重复的开头,后面所有重复的都要去掉
                //找到后面那个不重复的结点
                while(t_node != NULL && t_node->val == node->val)
                {
                    t_node = t_node->next;
                }
                last_last_node->next = t_node;
                //删除后需要恢复last_node和node的状态
                last_node = t_node;
                if(t_node != NULL)
                {
                    node = last_node->next;
                }else{
                    node = NULL;
                }
                continue;
            }
    
            //更新状态
            last_last_node = last_node;
            last_node = node;
            node = node->next;
        }
    
        return pHead;
    }
    

    上面的代码,当样例为 1 1 1 2 3 4开头就出现重复时无法通过. 后来经过思考,即使处理了开头重复的问题在遇到类似1 1 1 1 2 2 2 2等连续重复的情况也有可能会崩掉,条件过于复杂,废弃.

  • 相关阅读:
    SpringMVC的拦截器
    artDialog双击会关闭对话框的修改
    artDialog弹出框使用
    解决从本地文件系统上传到HDFS时的权限问题
    JAVA中写时复制(Copy-On-Write)Map实现
    数据结构--堆的实现(下)
    二叉树的创建算法
    Lamport Logical Clock 学习
    动态规划的思想来求解字符串分割问题
    数据结构--图 的JAVA实现(下)
  • 原文地址:https://www.cnblogs.com/virgildevil/p/12196798.html
Copyright © 2011-2022 走看看