【R&A】extracts&intersection-of-two-linked-lists-lcci

摘录

关于动机来源的理论:

  • 驱力与诱因:生物体就其本身条件来说如体温和能量供应等,会寻求一种动态平衡。当某种需要的平衡被打破,产生某种心理上的紧张,驱力就会被唤醒,促使生物体采取消除紧张的行为。当这些驱力得到满足或消除时,动态平衡得到恢复,生物体就会停止相应的行为。例如长期没有吃东西时,就会产生饥饿感从而诱发出寻找食物和进食的行为。但是,单纯的驱力无法解释人们熬夜刷手机而不去好好地睡上一觉的现象,类似现象可以解释为环境因素作为诱因在激发你的行为。综合驱力与诱因,可以发现行为是由内部和外部动机同时作用的结果。
  • 逆转理论:假定了四对元动机状态及其派生的动机模式(例如有目的&超越目的、顺从&逆反、控制&同情、自我中心&他人取向),任何时候,每队动机的两个状态中只有一个能被激活,并且试图解释人们是如何从对立的一端转向另一端。
  • 本能行为与学习:生物体有许多行为受本能所控制,通常对物种生存至关重要,是由基因遗传所决定的,例如心跳。但实际上判断行为是否属于本能的标准并不是那么明确,例如情感。用本能来广泛解释人类行为的观点因受到强烈批评而动摇。后来观点得到了改进,认为行为是先天本能与后天学习的组合。
  • 动机的期望与认知取向:人们的认知思想过程在决定其目的以及实现该目的的行为上有着极为重要的作用。有些行为仅仅是被一种期望所激发的,这个期望就是得到他们所需东西的可能性,例如抽奖。期望可以与动机的内部和外部力量联系起来,当人们认为行为的结果(例如考试分数差),归因于内在特质(例如缺乏努力或不够聪明),那下次就可能会更加努力;或者归因于外界因素(例如考试不公平或老师有偏见),那么下次就可能放弃努力。因此,把动机来源看作内部或外部,在一定程度上依赖于你对客观实体的主观认识。

链表相交

  • 方法1:暴力解法
  • 思路:遍历A,在A指向下一节点之前,遍历B,找出与当前A相同的节点,有则返回,无则下一轮
  • 代码:
ListNode* getIntersectionNode(ListNode *headA, ListNode *headB) {
    ListNode *ptrA = headA;
    ListNode *ptrB = headB;
    while(ptrA != nullptr) {
        while(ptrB != nullptr) {
            if(ptrB == ptrA) {
                return ptrB;
            } else {
                ptrB = ptrB->next;
            }
        }
        ptrA = ptrA->next;
        ptrB = headB;
    }
    return nullptr;
}
int main() {
    int del = 6;
    // 根据数组创建链表,需要反向遍历
    vector<int> nums = {4};
    ListNode* head1 = nullptr;
    for (vector<int>::reverse_iterator it = nums.rbegin(); it != nums.rend(); it++) {
        head1 = new ListNode(*it, head1);
    }
    ListNode* headA = new ListNode(123, head1);
    ListNode* headB = new ListNode(234, head1);
    ListNode* ptr = getIntersectionNode(headA, headB);
    cout<<ptr->val;
    return 0;
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

  • 方法2:尾部对齐再同时遍历
  • 思路:通过求两个链表的长度差来让两个链表尾部对齐,然后指针同时前进,找到相同的节点就返回,否则返回NULL
  • 过程图:
尾部对齐
  • 代码
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    ListNode* curA = headA;
    ListNode* curB = headB;
    int lenA = 0, lenB = 0;
    // 通过求两个链表的长度差来让两个链表尾部对齐
    while (curA != NULL) { // 求链表A的长度
        lenA++;
        curA = curA->next;
    }
    while (curB != NULL) { // 求链表B的长度
        lenB++;
        curB = curB->next;
    }
    curA = headA;
    curB = headB;
    // 通过swap交换函数,让curA为最长链表的头,lenA为其长度
    if (lenB > lenA) {
        swap (lenA, lenB);
        swap (curA, curB);
    }
    // 求长度差
    int gap = lenA - lenB;
    // 让curA和curB在同一起点上(末尾位置对齐)
    while (gap--) {
        curA = curA->next;
    }
    // 遍历curA 和 curB,遇到相同则直接返回
    while (curA != NULL) {
        if (curA == curB) {
            return curA;
        }
        curA = curA->next;
        curB = curB->next;
    }
    return NULL;
}
  • 优化:使用快慢原则
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    ListNode* curA = headA;
    ListNode* curB = headB;
    bool A2B = false;
    bool B2A = false;
    // 根据快慢法则,走的快的一定会追上走得慢的。
    // 在这道题里,有的链表短,他走完了就去走另一条链表,我们可以理解为走的快的指针。
    // 那么,只要其中一个链表走完了,就去走另一条链表的路(每条链表只走一次,最后都走A+B个节点)。如果有交点,他们最终一定会在同一个位置相遇
    while (curA != NULL && curB != NULL) {
        if (curA == curB) {
            return curA;
        }
        // 逗号表达式:从左到右执行,返回最右边的结果
        curA = curA->next ? curA->next : A2B ? NULL : (A2B = true, headB);
        curB = curB->next ? curB->next : B2A ? NULL : (B2A = true, headA);
    }
    return NULL;
}
  • 时间复杂度:O(n + m)
  • 空间复杂度:O(1)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容