剑指offer题目练习(五)

题目四十一

对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”

思路:三次reverse即可,以n作为分割点

class Solution {
public:
    string LeftRotateString(string str, int n) {
        if(str.size()<=0 || str.size()< n){
            return str;
        }
        reverseString(str,0,n-1);
        reverseString(str,n,str.size()-1);
        reverseString(str,0,str.size()-1);
        return str;
    }
    
    void reverseString(string & str,int begin,int end){
        while (begin < end){
            swap(str[begin++],str[end--]);
        }
    }
};
题目四十二

翻转字符串,例如,“student. a am I”。把句子单词的顺序翻转了,正确的句子应该是“I am a student.”

思路:上一道题是通过n来进行部分翻转,本题可以使用空格为标记进行翻转,先整体翻转,然后遇到空格翻转

class Solution {
public:
    string ReverseSentence(string str) {
        int size = str.size();
        reverseString(str,0,size-1);
        int i = 0;
        int begin = 0;
        int end = 0;
        while (i < size){
            while (i < size && str[i] == ' '){
                i++;
            }
            begin = end = i;
            while (i < size && str[i] != ' '){
                end++;
                i++;
            }
            reverseString(str,begin,end-1);
        }
        return str;
    }
    
    void reverseString(string & str,int begin,int end){
        while (begin < end){
            swap(str[begin++],str[end--]);
        }
    }
};
题目四十三

一副扑克大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。 现在, 如果5张牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

思路:可以将顺子转换为数组来思考,一个数组有五个数,除了0其他都不可以重复,最大值减去最小值要小于5。

bool IsContinuous( vector numbers ) {
        if (numbers.size() != 5){
            return false;
        }
        map mp;
        mp[14] = {0};
        int max = -1;
        int min = 14;
        
        for (int i = 0;i < numbers.size();i++){
            mp[numbers[i]]++;
            if (numbers[i] == 0){
                continue;
            }
            if (mp[numbers[i]] > 1){
                return false;
            }
            if (numbers[i] > max){
                max = numbers[i];
            }
            if (numbers[i] < min){
                min = numbers[i];
            }
        }
        
        if (max - min < 5){
            return true;
        }else{
            return false;
        }
        
    }
题目四十四

有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)。如果没有小朋友,请返回-1。

思路:可以使用一个数组模拟这个圈,被删除的数字在数组中设置为-1,遍历数组。

int LastRemaining_Solution(int n, int m)
    {
        if (n < 1 || m < 1){
            return -1;
        }
        vectorloop_arr;
        for (int i = 0;i < n;i++){
            loop_arr.push_back(i);
        }
        //圈中的小朋友数量
        int count = n;
        //最后小朋友的下标
        int i = -1;
        //步数
        int step = 0;
        while(count > 0){
            i++;
            //模拟圆圈
            if (i >= n){
                i = 0;
            }
            //当前已被删除
            if (loop_arr[i] == -1){
                continue;
            }
            step++;
            //M-1位要删除
            if (step == m){
                loop_arr[i] = -1;
                count--;
                step = 0;
            }
        }
        
        return i;
    }
题目四十五

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思路:可以使用&&来进行判断

int Sum_Solution(int n) {
        int sum = n;
        sum && ( sum +=Sum_Solution(n-1));
        return sum;
    }
题目四十六

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

思路:长度为n的数组,所有的数字又都在0~n-1的范围内,如果这个数组是排序的那么每个数的下标一定等于下标,利用这一点进行数组的重排。

bool duplicate(int numbers[], int length, int* duplication) {
        if (length <= 0){
            return false;
        }
        
        for (int i = 0;i length -1){
                return false;
            }
        }
        for (int i = 0;i < length;i++){
            while (numbers[i] != i){
                if (numbers[i] == numbers[numbers[i]]){
                    *duplication = numbers[i];
                    return true;
                }else{
                    int temp = numbers[i];
                    numbers[i] = numbers[temp];
                    numbers[temp] = temp;
                }
            }
        }
        return false;
    }
题目四十七

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。如果当前字符流没有存在出现一次的字符,返回#字符。

思路:借助哈希表来进行判断

class Solution
{
public:
  //Insert one char from stringstream
    string s;
    char mp[256] = {0};
    void Insert(char ch)
    {
        s += ch;
        mp[ch]++;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        for (int i = 0;i < s.size();i++){
            if (mp[s[i]] == 1){
                return s[i];
            }
        }
        return '#';
    }

};
题目四十八

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路:可以设置两个指针,一个走得快,一个走的慢,如果存在环那么两个指针会相遇,再判断环中节点的数量。然后重新设置两个指针,一个先走环中的数量相等的步数,然后两个一起走,相遇的地方就是入口。

ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if (pHead == nullptr){
            return nullptr;
        }
        //设置快慢指针,快的每次走两步,慢的每次一步,如果包含环,两个指针一定会相遇
        ListNode *pAhead = pHead;
        ListNode *pBack = pHead->next;
        if (pBack != nullptr && pAhead != nullptr && pBack != pAhead){
            pBack = pBack->next;
            pAhead = pAhead->next;
            if (pAhead->next != nullptr){
                pAhead = pAhead->next;
            }
        }
        //判断环中有几个节点
        int count = 1;
        ListNode *temp = pAhead->next;
        if (pAhead == pBack && pAhead != nullptr){
            while (pAhead != temp){
                count++;
                temp = temp->next;
            }
        }else{
            return nullptr;
        }
        ListNode *firstNode = pHead;
        ListNode *secondNode = pHead;
        for (int i = 0;i < count;i++){
            firstNode = firstNode->next;
        }
        while(firstNode != secondNode){
            firstNode = firstNode->next;
            secondNode = secondNode->next;
        }
        return secondNode;
    }
题目四十九

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

思路:借助前后指针,找到连续重复的最后一个节点,然后将pre与其下一个node链接

 ListNode* deleteDuplication(ListNode* pHead)
    {
        if (pHead == nullptr){
            return nullptr;
        }
        //设置当前节点,前节点,后节点
        ListNode *pre = nullptr;
        ListNode *pNode = pHead;
        ListNode *pNext = nullptr;
        
        while (pNode != nullptr){
            //判断当前节点是否与下一个节点相同
            if (pNode->next != nullptr && pNode->next->val == pNode->val){
                //相同则next设置为pNode->next
                pNext = pNode->next;
                //再判断下一个节点是否其下一个节点相同
                while (pNext->next != nullptr && pNext->val == pNext->next->val){
                    pNext = pNext->next;
                }
                //如果头结点发生重复,则直接将其链接为下一个不重复的节点
                if (pNode == pHead){
                    pHead = pNext->next;
                }else{
                    pre->next = pNext->next;
                }
                //设置pNoode为下一个不重复的节点
                pNode = pNext->next;
            }else{
                pre = pNode;
                pNode = pNode->next;
            }
        }
        
        return pHead;
    }
题目五十

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思路:先理清思路,如果这个节点有右子树,那么下一个节点就是右子树的最左子节点,如果没有右子树,但是这个节点是其父节点的左子节点,那么下一个就是它的父节点,如果上述条件都不满足,那么就要沿着指针一直寻找,知道找到一个节点是其父节点的左子节点,下一个就是其父节点。

TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if (pNode == nullptr){
            return nullptr;
        }
        TreeLinkNode *nextNode = nullptr;
        if (pNode->right != nullptr){
            TreeLinkNode *rightNode = pNode->right;
            while(rightNode->left){
                rightNode = rightNode->left;
            }
            nextNode = rightNode;
        }else if (pNode->next != nullptr){
            TreeLinkNode *parentNode = pNode->next;
            TreeLinkNode *currentNode = pNode;
            while (parentNode != nullptr && parentNode->right == currentNode){
                currentNode = parentNode;
                parentNode = currentNode->next;
            }
            nextNode = parentNode;
        }
        
        return nextNode;
    }

你可能感兴趣的:(剑指offer题目练习(五))