题目四十一
对于一个给定的字符序列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;
}