数据结构-线性表

算法题主要来自剑指offer上面的题目,本章主要是重新复习下线性表及其相关的算法题。

二维数组中的查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution {
public:
    bool Find(vector<vector<int> > array,int target) {

        bool isFind = false;
        if (array.size() == 0) {
            return isFind;
        }
        int currentRow = 0;
        int currentColumn = array[0].size() - 1;
        while (currentRow <= array.size()-1 && currentColumn >= 0) {
            vector<int> rowVector = array[currentRow];
            if (rowVector[currentColumn] > target) {
                currentColumn--;
            }else if (rowVector[currentColumn] < target){
                currentRow++;
            }else{
                // 相等,说明找到
                isFind = true;
                return isFind;
            }
        }
        return isFind;        
    }
};

从尾到头打印链表

输入一个链表,从尾到头打印链表每个节点的值。

输入描述

输入为链表的表头

输出描述

输出为需要打印的“新链表”的表头

/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) : * val(x), next(NULL) { * } * }; */
class Solution {
public:
    vector<int> printListFromTailToHead(struct ListNode* head) {
          stack<int> stack;
    vector<int> result;
    ListNode *pNode = head;
    if (pNode == NULL) {
        return result;
    }
    while (pNode!= NULL) {
        stack.push(pNode->val);
        pNode = pNode->next;
    }
    while (!stack.empty()) {
        result.push_back(stack.top());
        stack.pop();
    }

    return result;

    }
};

链表中环的入口结点

一个链表包含环,请找出该链表的环的入口结点

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */
class Solution {
public:

/** * 找出两个快慢结点相遇的结点 * * @param pHead <#pHead description#> * * @return <#return value description#> */
ListNode* meetNode(ListNode* pHead){

    // 慢结点,每次移动1步
    ListNode *pSlowNode = pHead;
    // 快结点,每次移动2步
    ListNode *pFastNode = pHead->next;
    if (pHead == NULL) {
        return NULL;
    }
    if (pHead->next == NULL) {
        return NULL;
    }
    while (pSlowNode != pFastNode) {
        pSlowNode = pSlowNode->next;
        pFastNode = pFastNode->next->next;
    }
    return pSlowNode;
}

/** * 求出头结点到相遇结点的距离 * * @param pHead <#pHead description#> * @param pMeetNode <#pMeetNode description#> * * @return <#return value description#> */
int distanceFormHeadToMeetNode(ListNode* pHead,ListNode* pMeetNode)
{
    int distance = 0;
    ListNode* pNode = pHead;
    while (pNode != pMeetNode) {
        distance++;
        pNode = pNode->next;
    }
    return distance;
}


ListNode* EntryNodeOfLoop(ListNode* pHead)
{
    if (pHead == NULL) {
        return NULL;
    }
    if (pHead->next == NULL) {
        return NULL;
    }
    ListNode* pNode1 = pHead;
    ListNode* pNode2 = pHead->next;
    ListNode* pMeetNode = meetNode(pHead);
    int distance = distanceFormHeadToMeetNode(pHead, pMeetNode);
    // pHead2先移动distance个距离
    while (distance != 0) {
        pNode2 = pNode2->next;
        distance--;
    }
    while (pNode1 != pNode2) {
        pNode1 = pNode1->next;
        pNode2 = pNode2->next;
    }
    return pNode1;
}

};

反转链表

输入一个链表,反转链表后,输出链表的所有元素。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode* pReversedHead = NULL;
        ListNode* pNode = pHead;
        ListNode* pPrev = NULL;
        while (pNode != NULL) {

            ListNode* pNext = pNode->next;
            if (pNext == NULL) {
                pReversedHead = pNode;
            }

            pNode->next = pPrev;
            pPrev = pNode;
            pNode = pNext;
        }
        return pReversedHead;
    }
};

链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

需要遍历两次的算法

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        // 先求出链表长度length,倒数第k个结点相当于第 length - k + 1个结点
        ListNode* pNode = pListHead;
    if (pListHead == NULL) {
        return NULL;
    }
    int length = 1;
    while (pNode != NULL) {
        length++;
        pNode = pNode->next;
    }
    pNode = pListHead;
    ListNode *pFindNode = NULL;
    // 取得了链表的长度length后,找到第 length - k + 1
    int count = 1;
    while (pNode != NULL) {
        count++;
        if (count == length - k + 1) {
            pFindNode = pNode;
            break;
        }
        pNode = pNode->next;
    }
    return pFindNode;
    }
};

只需遍历一次的算法(使用两个指针)(注意代码的鲁棒性

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if (pListHead == NULL || k== 0) {
            return NULL;
        }
        ListNode* pAheadNode = pListHead;
        ListNode* pBehind = pListHead;
        for (int i = 0; i < k-1; i++) {
             // pAheadNode向前移动
            if (pAheadNode->next != NULL) {
                pAheadNode = pAheadNode->next;
            }else{
                return NULL;
            }
        }
        while (pAheadNode->next != NULL) {
            pBehind = pBehind->next;
            pAheadNode = pAheadNode->next;
        }
        return pBehind;
    }
};

合并两个排序的链表(注意采用递归的思想)

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

不用递归的思想

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
    ListNode* pHead = NULL;
    ListNode* pLast = NULL;
    if (pHead1 == NULL && pHead2 == NULL) {
        return NULL;
    }else if (pHead1 == NULL && pHead2 != NULL){
        return pHead2;
    }else if (pHead1 != NULL && pHead2 == NULL){
        return pHead1;
    }else{
        ListNode* pNode1 = pHead1;
        ListNode* pNode2 = pHead2;

        // 先找出链表的头结点
        if (pNode1->val <= pNode2->val) {
            pHead = pNode1;
            pNode1 = pNode1->next;
        }else{
            pHead = pNode2;
            pNode2 = pNode2->next;
        }
        pLast = pHead;
        while (pNode1 != NULL || pNode2 != NULL) {
            ListNode* pNode = NULL;
            if (pNode1 == NULL) {
                pLast->next = pNode2;
                return pHead;
            }
            if (pNode2 == NULL) {
                pLast->next = pNode1;
                return pHead;
            }
            if (pNode1->val <= pNode2->val) {
                pNode = pNode1;
                pNode1 = pNode1->next;
            }else{
                pNode = pNode2;
                pNode2 = pNode2->next;
            }
            // 找到最小的结点后,最后一个结点指向该结点
            pLast->next = pNode;
            pLast = pNode;
        }
    }
    return pHead;
    }
};

使用递归的思想

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if (pHead1 == NULL) {
        return pHead2;
    }
    if (pHead2 == NULL) {
        return pHead1;
    }
    ListNode* pHead = NULL;
    if (pHead1->val < pHead2->val) {
        pHead = pHead1;
        pHead->next = Merge(pHead1->next, pHead2);
    }else{
        pHead = pHead2;
        pHead->next = Merge(pHead1, pHead2->next);
    }
    return pHead;
    }
};

复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:

RandomListNode* Clone(RandomListNode* pHead)
    {
        if(!pHead) return NULL;
        RandomListNode *currNode = pHead;
        while(currNode){
            RandomListNode *node = new RandomListNode(currNode->label);
            node->next = currNode->next;
            currNode->next = node;
            currNode = node->next;
        }
        currNode = pHead;
        while(currNode){
            RandomListNode *node = currNode->next;
            if(currNode->random){               
                node->random = currNode->random->next;
            }
            currNode = node->next;
        }
        //拆分
        RandomListNode *pCloneHead = pHead->next;
        RandomListNode *tmp;
        currNode = pHead;
        while(currNode->next){
            tmp = currNode->next;
            currNode->next =tmp->next;
            currNode = tmp;
        }
        return pCloneHead;
    }

};

两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {
         if (pHead1 == NULL || pHead2 == NULL) {
        return NULL;
    }
    // 分别计算两个链表的长度
    int length1 = 1;
    int length2 = 1;
    ListNode* pNode1 = pHead1;
    ListNode* pNode2 = pHead2;
    while (pNode1->next != NULL) {
        length1++;
        pNode1 = pNode1->next;
    }
    while (pNode2->next != NULL) {
        length2++;
        pNode2 = pNode2->next;
    }
    // 比较两个链表的长度
    int distance = length1 - length2;
    if (distance > 0) {
        // 说明链表1的长度长,链表1先走distance步。
        while (distance > 0) {
            pHead1 = pHead1->next;
            distance--;
        }
    }else{
        // 链表2的长度长
        distance = -distance;
        while (distance > 0) {
            pHead2 = pHead2->next;
            distance--;
        }
    }

    ListNode* commonNode = NULL;
    // 此时两个链表走的长度是相同的,可以同时遍历
    while (pHead1 != pHead2 && pHead1 != NULL && pHead2 != NULL) {
        pHead1 = pHead1->next;
        pHead2 = pHead2->next;
    }
    commonNode = pHead1;
    return commonNode;
    }
};

删除链表中重复的结点

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

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */
// 递归
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if (pHead==NULL)
            return NULL;
        if (pHead!=NULL && pHead->next==NULL)
            return pHead;

        ListNode* current;

        if ( pHead->next->val==pHead->val){
            current=pHead->next->next;
            while (current != NULL && current->val==pHead->val)
                current=current->next;
            return deleteDuplication(current);                     
        }

        else {
            current=pHead->next;
            pHead->next=deleteDuplication(current);
            return pHead;
        }    
    }
};

旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

点赞