1.调整数组顺序使奇数位于偶数前面
思路:维护两个指针,第一个指针指向第一个数字,从前向后,第二个指针指向数组的最后一个数字,从后往前。如果第一个指针指向的是偶数,第二个指针指向的是奇数,那么就交换这两个数字。终止条件是,第一个指针和第二个指针相遇。

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        if(array.size()<2) return;
        int i=0,j=array.size()-1;
        while(i<j)
        {
            while(i<j&&!isEven(array[i]))
                i++;//定位第一个偶数
            while(i<j&&isEven(array[j]))
                j--;//定位第一个奇数
            if(i<j)
            {
                int temp=array[i];
                array[i]=array[j];
                array[j]=temp;
            }
        }
    }
    bool isEven(int n)
    {
        return(n&1)==0;
    }
};

如果顺序不可以改变呢?

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        int len=array.size();
        for(int i=0;i<len;i++)
        {
            for(int j=len-1;j>i;j--)
            {
                if(array[j]%2==1&&array[j-1]%2==0)
                {
                    swap(array[j-1],array[j]);
                }
            }
        }
        /*新建一个数组
        vector<int> result;
        int num=array.size();
        for(int i=0;i<num;i++)
        {
            if(array[i]%2==1)
                result.push_back(array[i]);
        }
        for(int j=0;j<num;j++)
        {
            if(array[j]%2==0)
                result.push_back(array[j]);
        }
        array=result;*/
    }
};

2.链表的倒数第k个节点
思路:维护两个指针,第一个指针从头结点开始先向前走k-1步,然后从第k步开始,第二个指针也开始从链表的头指针开始遍历,当第一个指针走到尾结点时,第二个指针到达倒数第k个节点。(注意鲁棒性,链表可能为空,k可能为0,可能不存在倒数第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) {
        if(pListHead==nullptr||k==0) return nullptr;//特殊情况一·
        ListNode* p1=pListHead;
        ListNode* p2=nullptr;
        for(int i=0;i<k-1;i++)
        {
            if(p1->next!=nullptr)
                p1=p1->next;
            else
                return nullptr;//特殊情况二
        }
        p2=pListHead;
        while(p1->next!=nullptr)
        {
            p2=p2->next;
            p1=p1->next;
        }
        return p2;
    }
};

3.链表中环的入口节点
思路:如何判断有环?定义快慢指针,快指针一次走两步,慢指针一次走一步,如果快的追上了慢的,那么代表有环。如何找到环的入口?如果链表的环上面有n个节点,维护两个指针,第一个先走n步,然后第二个节点开始走,二者相遇的节点即为环的入口节点。如何找环上有几个节点?快慢指针相遇一定是在环中,从相遇节点出发,当再次回到这个节点时,可以得到环中节点的个数。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* MeetingNode(ListNode* pHead)
    {
        if(pHead==nullptr)
            return nullptr;
        ListNode* pSlow=pHead->next;
        if(pSlow==nullptr)
            return nullptr;//只有一个或没有节点
        ListNode* pFast=pSlow->next;
        while(pFast!=nullptr&&pSlow!=nullptr)
        {
            if(pFast==pSlow)
                return pFast;
            pSlow=pSlow->next;
            pFast=pFast->next;
            if(pFast!=nullptr)
                pFast=pFast->next;
        }//注意不要走到空指针
        return nullptr;
    }
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        ListNode* meetingNode=MeetingNode(pHead);
        if(meetingNode==nullptr)
            return nullptr;
        int nodeInLoop=1;
        ListNode* p1=meetingNode;
        while(p1->next!=meetingNode)
        {
            p1=p1->next;
            nodeInLoop++;
        }
        p1=pHead;
        for(int i=0;i<nodeInLoop;i++)
        {
            p1=p1->next;//先走环的数量步
        }
        ListNode* p2=pHead;
        while(p1!=p2)
        {
            p1=p1->next;
            p2=p2->next;
        }
    }
};

方法二:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    //设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点
    //(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        ListNode *fast=pHead;
        ListNode *low=pHead;
        while(fast!=NULL&&fast->next!=NULL)
        {
            fast=fast->next->next;
            low=low->next;
            if(fast==low)
                break;
        }
        if(fast==NULL||fast->next==NULL) return NULL;
        low=pHead;
        while(low!=fast)//用while更好
        {
            fast=fast->next;
            low=low->next;         
        }
        return low;
    }
};

4.反转链表
思路:维护三个指针,分别指向当前遍历的节点,他的前一个和后一个节点。注意翻转后链表的头结点即原链表的尾结点。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead==nullptr||pHead->next==nullptr) return pHead;
        ListNode *pReversedHead=nullptr;//用于记录最后一个节点
        ListNode *pNode=pHead;//当前节点
        ListNode *pPrev=nullptr;//当前节点的前一个节点
        while(pNode!=nullptr)
        {
            ListNode* pNext=pNode->next;
            if(pNext==nullptr)
                pReversedHead=pNode;//如果pNode到达尾结点,令此节点等于pNode
            pNode->next=pPrev;
            pPrev=pNode;
            pNode=pNext;           
        }
        return pReversedHead;
    }
};

方法二:利用堆栈

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        //利用堆栈
        if(pHead==NULL||pHead->next==NULL) return pHead;//一个结点或没有,直接返回
        stack<ListNode*> rev;
        ListNode *p=pHead;
        while(p->next)//把最后一个结点留下
        {
            rev.push(p);
            p=p->next;
        }
        ListNode *head=p;//新的头结点等于原链表的最后一个结点
        while(!rev.empty())//尾插法
        {
            p->next=rev.top();
            p=p->next;
            rev.pop();     
        }
        p->next=NULL;//最后一个结点指向NULL
        return head;       
    }
};