算法学习记录(三)--链表结束

不知不觉离上篇算法博客将近一个月时间,稍不留神时间就过去,学习算法是相当不容易的事
今天把链表相关题目练习完

1. 反转链表

分析:原始链表的尾部是新链表的头部,所以要currentHead->next = newHeader
时间复杂度:o(n)
空间复杂度:o(1)

void invertListNode(Node *header){
    // 1.如果是空或者如果只有一个,直接return
    if(header == NULL || header->next == NULL){
        return;
    }
    // 2.开始遍历,将新下一个结点放在头结点的前边
    Node *NewHeaderNode = NULL;
    Node *currentHeadNode = header;
    while (currentHeadNode != NULL) {
        // 1.取当前头结点
        Node *tempNode = currentHeadNode;
       // 2.当前结点的尾部指向新链表的头部
        tempNode->next = NewHeaderNode;
       // 3. 当前结点后移
        currentHeadNode = currentHeadNode->next;
       // 4. 新头结点赋值
        NewHeaderNode = tempNode;
    }
}
2. 倒序第k个结点

分析:若先遍历到尾部,然后再来一个头指针遍历一次,需要时间复杂度o(n+k),可以用两个指针一前一后操作,先让头指针先遍历k个点,然后同时开始操作,第一个指针遍历到尾部,第二个指针的位置就是了
时间复杂度:o(n)
注意:判断链表的长度是否比k大

Node *lastKNode(Node *header, int k){
    if(k < 0 || header == NULL) return NULL;
    // 1.先遍历到第k个结点
    Node *tempHeader = header;
    while (tempHeader && k > 0) {
        k--;
        tempHeader = tempHeader->next;
    }
    if(k > 0) return NULL;
    // 2.再来一个指针从头遍历,第一个遍历完毕,第二个就是
    Node *tempHeader2 = header;
    while (tempHeader) {
        tempHeader = tempHeader->next;
        tempHeader2 = tempHeader2->next;
    }
    return tempHeader2;
}
3. 中间结点

分析:这个叫快慢指针,跟上题的思路类似,快指针一次遍历两个结点,快指针走到头,慢指针所指的位置就是
注意:判断链表的长度是0、1、2

Node *middleNode(Node *header){
    // 1.合法性判断
    if(header == NULL) return NULL;
    if(header->next) return header;
    if(header->next->next) return header;
    // 2.使用快慢指针
    Node *before = header;
    Node *behind = header;
    while (before->next) { //如果快指针走到头,遍历结束
        before = before->next;
        behind = behind->next;
        if(before){
            before = before->next;
        }
    }
    return behind;
}
4.合并两个有序单链表

分析:从两个链表的头部开始,新链表的当前节点谁得大取谁得
时间复杂度:o(max(len1,len2))
空间复杂度:o(1)

Node * mergeTwoSortList(Node *header1, Node *header2){
    // 1.判断
    if(header1 == NULL) return header2;
    if(header2 == NULL) return header1;
    
    // 2.准备合并,先找第一个节点,要不然还得在while循环中判断;所以单拿出来操作
    Node *newHeader = NULL;
    if(header1->value < header2->value){
        newHeader = header1;
        header1 = header1->next;
    }else if(header1->value > header2->value){
        newHeader = header2;
        header2 = header2->next;
    }else{
        newHeader = header1;
        newHeader->next = header2;
        header1 = header1->next;
        header2 = header2->next;
    }
    Node *tempNode = newHeader;
    // 3.开始合并
    while (header1->next && header2->next) {
        if(header1->value < header2->value){
            tempNode->next = header1;
            tempNode = tempNode->next;
            header1 = header1->next;
        }else if(header1->value > header2->value){
            tempNode->next = header2;
            tempNode = tempNode->next;
            header2 = header2 -> next;
        }else{
            // 新链表指向header1结点
            tempNode->next = header1;
            // header1下移
            header1 = header1->next;
            // 新链表头指针下移
            tempNode = tempNode->next;
            // 同上,操作header2头结点
            tempNode->next = header2;
            header2 = header2->next;
            tempNode = tempNode->next;
        }
    }
    // 4. 合并剩余的部分
    if(header1){
        tempNode->next = header1;
    }
    if(header2){
        tempNode->next = header2;
    }
    return newHeader;
}
5. 链表有环

思路:说明链表永远遍历不完,那么可以用快慢指针操作,一个指针走一步,一个走两步,在某一个时刻两个指针必然指向同一个值
时间复杂度:o(n)
空间复杂度:o(1)

bool nodeHasCircle(Node *header){
    if(header == NULL) return false;
    Node *before = header;
    Node *behind = header;
    while (before) {
        before = before->next;
        if(before){
            before = before->next;
        }
        behind = behind->next;
        if(before == behind) return true;
    }
    return false;
}
6. 链表交叉

思路:

  1. 将第二个链表头结点连接在第一个结点尾部,若相交则新链表必然有环,可以用上方有环操作判断
    时间复杂度:o(len2)
bool nodeCross(Node *node1,Node *node2){
    // 1.合法判断
    if(node1 == NULL || node2 == NULL) return false;
    // 3. 将第二个链表指向第一个连标点尾部
    Node *header1 = node1;
    while (header1->next) {
        header1 = header1->next;
    }
    header1->next = node2;
    return nodeHasCircle(node2);
}
  1. 若两个链表相交,则交点之后的结点是两个链表共有的,换句话说两个链表的尾结点肯定是同一个,则:分别遍历两个链表到尾部,若尾部相等则相交
    时间复杂度:o(len1+len2)
bool nodeCross(Node *node1,Node *node2){
    // 1.合法判断
    if(node1 == NULL || node2 == NULL) return false;
    // 2.分别遍历到尾部,比较尾部是否相等
    Node *header1 = node1;
    Node *header2 = node2;
    while (header1->next) { //判断尾部
        header1 = header1->next;
    }
    while (header2->next) {
        header2 = header2->next;
    }
    if(header1 == header2){
        return true;
    }
}
  1. 求链表交点
    分析:由于两个链表相交,则从交点到尾部都相等;链表的长度之差为:len1-len2 = k,则长链表先走k部之后,再同时走,必然相遇
    时间复杂度:0(len1+len2+k+2*n),各自遍历求长度复杂度分别为o(len1)、o(len2),然后长链表先走k步,再各自走n步,总共就是这么多复杂度
    空间复杂度:o(1)
Node *crossNode(Node *node1,Node *node2){
    if(node1 == NULL || node2 == NULL) return NULL;
    // 1.计算长度
    int len1 = 0;
    int len2 = 0;
    Node *header1 = node1;
    Node *header2 = node2;
    while (header1) {
        header1 = header1->next;
        len1++;
    }
    while (header2) {
        header2 = header2->next;
        len2++;
    }
    // 长度为k
    int k = len2>len1? len2-len1:len1-len2;
    // 2.分情况遍历
    if(len2 > len1){
        // 2.1 长链表先走k部
        while (k > 0) {
            node2 = node2->next;
            k--;
        }
        // 2.2 两个链表同时走,啥时候相等啥时候就是交点
        while (node1 && node2) {
            if(node1 == node2){
                return node1;
            }
            node2 = node2->next;
            node1 = node1->next;
        }
    }else{
        while (k > 0) {
            node1 = node1->next;
            k--;
        }
        while (node1 && node2) {
            if(node1 == node2){
                return node2;
            }
            node2 = node2->next;
            node1 = node1->next;
        }
    }
    return NULL;
}
  1. 求链表环入口
    涉及一个公式推导,有点儿烦躁!主要我没带笔,只能用脑子想,借笔也没借到,抬头一看咖啡馆里有个用pc玩穿越火线的,立刻回想起大一的日子~
    思路:先推导公式:a = (n-1)c+(c-x)[推导过程可以参考下文章,c表示环的长度],由推导公式可知,若两个指针p1,p2分别从头结点和相遇点同时移动,且速度相等,则p1移动到入口点时,p1移动了a距离,p2移动了a=(n-1)c+(c-x)=nc-x距离,也是入口点(相当于绕了n圈,然后倒退了x距离,由下图可知正好也是入口点),那么就找到了这个入口点
    参考 判断链表是否有环,环的入口以及环的长度
image
Node *circleStartNode(Node *header){
    if(header == NULL) return NULL;
    // 1.找到相遇点
    Node *before = header;
    Node *behind = header;
    BOOL flag = false;//标记是否有环
    while (before) {
        before = before->next;
        if(before){
            before = before->next;
        }
        behind = behind->next;
        if(before == behind){
            flag = true;
            break;
        }
    }
    // 无环,直接返回
    if(flag == false) return NULL;
    // 2.定义两个指针,再次遍历
    Node *startNode = header;
    Node *meetNode = before;
    while (startNode) {
        //如果两个结点相等,就是要找的入口点
        if(startNode == meetNode){
            return startNode;
        }
        startNode = startNode->next;
        meetNode = meetNode->next;
    }
    return NULL;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351