题目1 孩子们的游戏(圆圈中最后剩下的数)[题目链接](https://www.nowcoder.com/practice/f78a359491e64a50bce2d89cff857eb6?tpId=13&tqId=11199&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
思路1 :模拟,很容易想到用循环链表模拟,选择何种形式来实现循环链表的功能呢?最开始想的是用数组来模拟循环链表,用一个数组来记录数字是否出局,若出局则跳过这个数字。 看到一个比较巧妙的思路,可以用一个队列来模拟循环链表,利用队列先进先出的特点,前面报数非为m的数依次加入队列,相当于一个滑动窗口,当报数为m-1时,直接出栈。
代码1 : 数组模拟(代码略复杂,下次回来改)
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if( n<=0 || m<=0)
return -1 ;
if (n == 1)
return 0;
int exit = 0 ;
int Count = 0, index=0;
bool isExit[n] ;
for(int i=0; i
代码2(队列模拟)
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n <=0 || m <=0)
return -1 ;
if(n == 1)
return 0 ;
queue tmp ;
for(int i=0; i 1)
{
for(int i=0; i
思路2 :找规律(具体数学中学过,待补)
题目2 扑克牌顺子[题目](https://www.nowcoder.com/practice/762836f4d43d43ca9deb273b3de8e1f4?tpId=13&tqId=11198&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 思路2:(1)除0外没有重复数字 (2)排序后,用num[i]-num[i-1]-1记录缺几张牌,计算0的个数(可变牌数),若可变牌>=缺的牌,则可组成顺子。 代码1 代码2 题目3 翻转单词顺序列 [题目](https://www.nowcoder.com/practice/3194a4f4cf814f63919d0790578d51f3?tpId=13&tqId=11197&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 思路2: 单指针从前往后扫描,巧妙利用string的连接操作。 代码1 : 代码2: 题目4 左旋转字符串 题目链接 代码2: 题目5 和为S的两个数字题目 题目6 和为S的连续正数序列题目 推广到一般情况: 正数数组,求正数子序列使得 和为s。可以用前缀和数组来计算,plow 到phigh之间的数字和可以表示为 sum[phigh]-sum[plow-1]。同样地用双指针,只要前缀和数组满足递增数列就可以cur>s, high 向左移,cur 代码 题目7 数组中只出现一次的两个数字题目 思路: 初看这题的时候,想到了异或操作, 任何数和0异或结果都是自身,相同的数异或为0。利用这个特性,如果数组中只有一个数字,那么可以找到那个数字。现在有两个这样的数字该怎么办呢?分组(分两组分别找),设只出现一次的数字是a和b,先把所有数字异或一遍,得到结果a xor b。a xor b二进制为1的位表明 a,b 在该位一个为0,一个为1. 利用这个性质把数字分为两组(相同的数字肯定在一组),a,b肯定被分在不同组,然后组内异或就可以得到结果了。 题目 8 平衡二叉树 题目 9 二叉树的深度 题目10 数字在排序数组中出现的次数 题目11 两个链表的第一个公共节点 思路:最开始的时候连题意都没有弄明白。先弄懂题意,两个链表若有公共节点的话,会表现像一个Y字,问题是两个链表长度不一样,若链表长度一样直接一一比较直到两个指针相同。skills :让长的链表先走 k步(k为两链表长度之差),然后两个链表一起走。快慢指针在链表操作中很常见,求链表的倒数第k个节点,也是先让一个指针走k步,然后另一个指针从头和当前指针一起走,当前指针走到尾节点的时候,头指针正好指向倒数第k个节点。 代码 题目 12 数组中的逆序对题目 题目13 第一个只出现一次的字母 题目14 丑数 代码:
题意:判断5张牌,是否组成顺子(大小王用0,表示,A表示0,J表示11)。
思路1:判断是否为顺子:(1) 长度为5 (2)除0外没有重复数字(3)max -min <5.推广到一般情况顺子长度为k, max -min class Solution {
public:
bool IsContinuous( vector
class Solution {
public:
bool IsContinuous( vector
题意:将单词序列翻转,如:“I am a student.”翻转后为“student. a am I”。
思路1 :(1)用指针p1扫描原字符串,并记录每个单词长度len,遇到空格时停止;(2)p2指向新字符串尾部;(3)p1复制给p2,p1向后走len步,p2向后走len步(4) p1+len回到空格处,将空格复制到新字符串中 。repeat上述过程,直到字符串结束。class Solution {
public:
string ReverseSentence(string str) {
int length = str.length() ;
if(length <=1)
return str ;
string res=str ;
int pstr=0, pres=length-1,pstart=0;
int len = 0 ;
while(str[pstr] != ' ' && pstr < length)
{
pstr ++ ;
len ++ ;
if(str[pstr] ==' ')
{
pstart = pstr - len ;
pstr -=1 ;
while(pstr>=pstart)
{
res[pres--]=str[pstr--];
}
pstr += len+1 ;
res[pres--] = str[pstr++] ;
len = 0 ;
}
if(pstr == length-1)
{
pstart = pstr - len ;
while(pstr>=pstart && pres >=0)
{
res[pres--]=str[pstr--];
}
break ;
}
}
return res ;
}
};
class Solution {
public:
string ReverseSentence(string str) {
int length = str.length() ;
if(length <= 1)
return str ;
string res="", tmp="" ;
for(int i=0; i
题意:str = XY 求输出YX
思路1 :直接利用字符串特性,取出X,Y,组合成YX
思路2:假设字符串abcdef,n=3,设X=abc,Y=def,所以字符串可以表示成XY,如题干,问如何求得YX。假设X的翻转为X,XT=cba,同理YT=fed,那么YX = (XTYT)T,三次翻转后可得结果。
代码1:class Solution {
public:
string LeftRotateString(string str, int n) {
int length = str.length() ;
if(length <= 1)
return str ;
n = n%length ;
string tmp = str.substr(0,n);
string tmp2 =str.substr(n, length-n);
return tmp2+tmp;
}
};
class Solution {
public:
void fun(string &s,int start,int end)
{
char temp;
while(start
题意:递增数列,求两个数字和为S,若有多组解,求使得乘积最小的那组。
思路:左右指针法,用两个指针从两头向中间逼近,a+b=s,a,b相差越大,a*b越小。
代码:class Solution {
public:
vector
题意:输出求和为S的连续正数序列,序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思路 :双指针法,两个指针分别放在数组的第一个数字和第二个数字处,比较数字的和来移动指针,cur = (plow + phigh)*(phigh-plow+1)/2 ,cur>s, high 向左移,cur
class Solution {
public:
vector
题意: 数组中只有两个数字只出现一次,剩下的都出现两次,找到那两个数字。
代码class Solution {
public:
int findFirst1(int num)
{
int bit = 1;
while((num & 1) == 0 && bit < 32) //记得加括号,运算符优先级 & 比==优先级低
{
bit ++ ;
num = num >> 1 ;
}
return bit ;
}
bool isBit1(int num, int bit)
{
for(int i=1; i
题意:判断一棵树是不是平衡二叉树
思路: 递归判断树的深度差是否为1, skills 深度大于0表示正常的深度, <0表示不平衡。
代码:class Solution {
public:
int getDepth(TreeNode *root, int depth)
{
if (depth < 0 )
return -1 ;
if (root == nullptr)
return depth ;
int leftDepth = getDepth(root->left, depth+1);
int rightDepth = getDepth(root->right,depth+1 ) ;
int diff = leftDepth - rightDepth ;
if (diff >1 || diff <-1)
return -1 ;
else return max(leftDepth, rightDepth) ;
}
bool IsBalanced_Solution(TreeNode* pRoot) {
int depth = getDepth(pRoot, 0) ;
if (depth < 0)
return false ;
else
return true ;
}
};
代码:class Solution {
public:
int getDepth(TreeNode *root, int depth)
{
if(root == nullptr)
return depth;
int leftDepth = getDepth(root->left, depth+1) ;
int rightDepth = getDepth(root->right, depth+1) ;
return max(leftDepth, rightDepth);
}
int TreeDepth(TreeNode* pRoot)
{
return getDepth(pRoot, 0) ;
}
};
思路:看见数组有序就想到 二分查找, 比较巧妙的思路是 k是整数,搜索k+0.5和k-0.5应该插入的位置,两者相减就得到了。
代码:class Solution {
public:
int GetNumberOfK(vector
class Solution {
public:
int GetListLength(ListNode * head)
{
int length = 0 ;
while(head)
{
length ++ ;
head = head->next ;
}
return length ;
}
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
int len1 = GetListLength(pHead1) ;
int len2 = GetListLength(pHead2) ;
int diff , flag;
if (len1 > len2)
{
diff = len1 - len2 ;
flag =1 ;
}
else {
diff = len2 - len1 ;
flag = 2 ;
}
if (flag == 1)
{
for (int i=1; i<= diff; i++)
pHead1 = pHead1->next ;
}
if (flag == 2)
{
for (int i=1; i <=diff; i++)
pHead2 = pHead2->next ;
}
while (pHead1 != nullptr && pHead2 != nullptr && pHead1 != pHead2)
{
pHead1 = pHead1->next ;
pHead2 = pHead2->next ;
}
return pHead1 ;
}
};
思路:能想到归并排序这题就出来啦,记得归并的时候从后到前,从前到后会有问题。(如:1 2 7 8、4 5 9 10归并的时候从右到左,8 可以轻易判断4,5都比8小,但是从 左到右的时候, 4,5已经归并进去了,9,10大于8,这样子计数是有问题的)。主代码中不要写太多递归,容易栈溢出
代码class Solution {
public:
int InversePairs(vector
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
思路: hash 表,桶排序。
代码:class Solution {
public:
int FirstNotRepeatingChar(string str) {
int len = str.length() ;
if(len <= 0)
return -1 ;
int res[100] ;
for(int i=0; i<100; i++)
res[i] = 0;
for(int i=0; i< len; i++)
{
res[str[i] -'A'] ++ ;
}
for(int i=0; i< len; i++)
{
if(res[str[i] -'A'] == 1)
return i ;
}
return -1;
}
};
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:最开始拿到这个题目的时候,第一反应是找规律(希望能发现数字间的规律)结果发现没有规律,不要直接陷入找规律中。有些规律可能不是以数字的形式呈现,可以多考虑堆栈队列等数据结构。
丑数是质因子只有2、3、5的数,也就是说每个丑数是由原来的丑数乘以2、3、5得到的,1乘以2、3、5得到2,3,5 依次乘以2,3,5得到4,6,10 ,6 ,9,15,10,15,25。这样得到的序列不是有序的且有重复。可以用3个队列来维护*2,*3,*5的结果。
1)丑数数组: 1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:5,10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
1.为什么分三个队列?
丑数数组里的数一定是有序的,因为我们是从丑数数组里的数乘以2,3,5选出的最小数,一定比以前未乘以2,3,5大,同时对于三个队列内部,按先后顺序乘以2,3,5分别放入,所以同一个队列内部也是有序的;
2.为什么比较三个队列头部最小的数放入丑数数组?
因为三个队列是有序的,所以取出三个头中最小的,等同于找到了三个队列所有数中最小的。
实现思路:
我们没有必要维护三个队列,只需要记录三个指针显示到达哪一步;class Solution {
public:
int GetUglyNumber_Solution(int index) {
if (index < 7)
return index ;
vector