摘要:给定N个数组,将其向右循环移动K位。此题在编程珠玑上曾经见过,先写个例子观察:abcdefg,向右移动3位 ->efgabcd。最简单的思路是循环将整个数组移动k位(这里k可以转化为k%=n,因为循环移位整个数组可以看成一个环),但是时间复杂度较高。然后,通过上述例子发现,循环移位后,数组的两个部分仅仅是移动了位置,其它不变,所以,可以用一个临时数组缓存较小的一部分,然后将较大的一部分移动到移位后的位置,再将较小的部分加入。但是,如果数组很大,可能空间复杂度会较大。第三个方法是通过对两部分分别逆序,再整个逆序达到效果:1、逆序abcd:abcdefg -> dcbaefg;2、逆序
阅读全文
摘要:解题思路:设数组为1,-1,2,-3,4,-5,6,-7从后向前迭代:-7首先直接放入临时数组(-7,1),1代表长度为1; 6,比-7大,所以不能和-7组合为递增序列,同时6肯定优于-7,所以置换为(6,1); -5比6小,可以和6组合为递增序列,(-5,2),(6,1); 4比6小,可以和6组合为递增序列,同时,4比-5大,所以置换为(4,2),(6,1); -3比6小,可以组合,同时,-3比4小,也可组合,添加,(-3,3),(4,2),(6,1); 2比6小,可以组合,2比4小,也可组合,2比-3大,置换(2...
阅读全文
摘要:从一个数组中找出两个数字,让这两个数字之和等于一个给定值。解题思路:第一印象是循环查找,从第一个数开始,取所有其后面的数与其相加,并判断是否为给定值。此复杂度为O(n2).这种复杂度为O(n2)的解法,又是在一个无序的数组中,可以尝试先将其排序,再看排序后是否可以简化循环过程。下面是一个排序后的数组:1,4,5,6,7,8,9想要找相加和为N,则设置两个指针指向两端(p指向第一个,q指向最后一个),如果当前所指两个数相加大于N,则说明不可能还有在q所指元素之后与q所指元素相加会小于等于N,所以指针q向前移,如果两个数相加小于N,说明不可能还有数在指针p所指元素之前与当前所指元素相加会大于等于N
阅读全文
摘要:解题思路:一种是存储递归过程中已经计算过的值,另一种是通过递推关系式;这是第二种方法:F(n) = F(n-1) + F(n-2)F(n-1) = F(n-2) + F(n-3)...F(4) = F(3) + F(2)F(3) = F(2) + F(1)F(2) = F(1) + F(0)可以看出自底向上,每一次求解的两个值都包含在前一次的公式中,用代码写就相当于:int t;t = a;a = a + b;b = t;每次只需要用一个临时变量保存第一个值,然后将其做为下一次迭代的第二个值就可以了。int Fibonacci(int n){ if (n <= 0) ret...
阅读全文
摘要:想要得到N个数中最大的K个数,典型的思路就是设置一个数组arr[K],然后遍历N个数,判断当前数和数组arr[k]中最小的数,如果它大于数组中最小的数,则置换。在这个数组中寻找最小的数,如果无序的话,很明显复杂度即为O(K),如果排序的话,维护一个有序数列,并且每次都是取该序列最小值进行比较,就自然地想到了小根堆了。下面是使用c++的stl中的堆算法实现的代码,由于stl只支持四种算法:push_heapPush element into heap range(function template)pop_heapPop element from heap range(function temp
阅读全文
摘要:直接用辗转相除法。即设f(x,y)为x,y最大公约数,则f(x,y) = f(y, x%y).主要的思路比较清晰,在这里记录一下辗转相除法的证明,就当找一找高中的感觉吧。。设:x,y(x>=y)最大公约数是c,证明x,x%y的最大公约数同样是c。1、x = k*y + r; r = x%y.2、设x = mc,y = nc;3、由1,2得:mc=knc +r,即:r=(m-kn)c;4、此时,只需证明m-kn与n是互素即可。反证:设m-kn与n非互素,则m-kn = ed,n =qd, => m = kn+ed = kqd+ed = (kq+e)d, 又x =mc = (kq+e)
阅读全文
摘要:第一题:求N!末尾有多少个0.解题思路:通过判断阶乘中每一个数包含的2和5的个数,取其中更小的那个数即为末尾0的个数。 更进一步观察发现,2的个数肯定比5的个数多,所以,只需要求5的个数。。。第二题:求N!的二进制表示中最低位1的位置。解题思路:其实,就是求阶乘结果中2的个数+1。上述两题都转化为求N!的质因数的个数,一种简单的思路就是循环获得小于等于N的每一个数所包含的质因数x的个数,最终得到的总数即为所求。第二种方法是:N!中要得到包含某个数k的个数,其实相当于[N/k] +[N/k2] +[N/k3] +[N/k4] +...。原理:首先,[N/k]等于1,2,3,...,N...
阅读全文
摘要:求节点最大距离,还是可以分解为求根节点最大距离和求它的左右子树的最大距离。这一题中,由于只需要得到最大距离,所以在每一步中获得当前根节点的最大距离,并与全局变量MaxLen比较即可;貌似这题没有什么重叠子问题,直接递归即可。正如书中所说,弄清楚递归的边界条件和每一步递归的顺序,对于递归过程做到心中有数,同时想好设置什么样的参数和返回值等以使得解决方法最简单,即可轻松实现这一类递归问题;int MaxLen = 0;int MaxDistance(const Node *root){ if (root->lchild == NULL && root->rchild =
阅读全文
摘要:通过一棵树的先序和中序的遍历结果,重建这棵树。解题思路:还是递归,每一次在先序字符串中获得当前的根节点后,在中序字符串中找到它的位置,然后计算它的左子树和右子树对应的字符串开始与结束位置,并继续求它的左子树和右子树。重点是找清楚每次获得两个字符串的起始和结束位置!结束条件是开始位置大于结束位置,返回NULL;只有当节点的信息不重复时,才能正确地求得一棵的树。#include<iostream>#include<string>#include<vector>#include<malloc.h>using namespace std;typedef
阅读全文
摘要:解题思路:一开始想到递归,发现用递归很难保证节点的访问顺序。(递归对于先,中,后序遍历都有效,但是对于层次遍历似乎没有找到可行的方法)按照层次遍历二叉树的做法,通常用一个队列来保证节点按照先入先出的顺序来。这题的关键是如何在使用队列时确定当前所处的层次,以保证输出的每一层节点为一行。解决办法是设置两个游标cur和last,cur指向当前处理的节点,last指向当前层的最后一个节点的下一个位置。每次内循环都是输出一整层的节点,并将它们的子节点入队列。void PrintNodeByLevel(const Node *root){ vector<const Node*> vec; ve
阅读全文
摘要:问题本身很简单,考虑扩展问题:如果链表有环的话,又或者求解相交的第一个节点,个人认为都是采用计数的方法比较适合。也就是说设置一个hash表,记录指针指向的地址,无论求是否有环或者找到第一个相交的节点都可以。唯一缺点是需要额外的空间。书上提到的第三个解法有些需要注意的地方:它不是一个线程安全的,因为在这个过程中,它改变的链表的结构(虽然最终会修改回来)。而且这种比较类型的功能函数一般都不应该更改它的值。LNode* JudgeIntersect(LNode *la, LNode *lb){ LNode *p = la, *q = lb; while(p != NULL){ ...
阅读全文
摘要:主要思想为递归求解,每一次都需要计算三种情况下的最小值。需要注意的是几个条件:1、一旦begin>end,则结束当前递归,返回值为0;2、如果当前pAbegin == pBbegin,则两个指针都直接跳到下一个字符;这里给出用map保存递归过程每一次的指针状态,以避免重复的递归计算(除结束状态,因为结束状态的计算无需递归,开销更小);定义MapCmp访函数做为排序准则时,需要注意满足三个条件,即strict weak ordering(反对称,可传递,非自反(这个容易遗忘));#include<iostream>#include<string>#include&l
阅读全文
摘要:主要思路就是递归遍历所有可能的单词;设置一个数字对应字符集的对照表vec,并设置一个数组count保存每个数字的字符集大小(为了避免在递归中使用str.length()所带来的性能开销);数组number保存输入的数字;设置一个flag数组,可以保存当前每一个数字所对应的字母下标;index记录当前处理到的数字在数组中的下标;n为输入号码长度;内存开销基本只有递归的开销比较大;(书上的循环解法真心没看懂,可是作者竟然说循环比递归简单,我了个擦。mark下)#include<iostream>#include<string>#include<vector>us
阅读全文
摘要:简单的方法就是直接将第一个字符串自加,然后查找其中是否有其子串。注意:find方法返回的是string::npos,它一般是-1,但是在我的机器上,是无符号数4294967295。1 #include2 #include3 using namespace std;45 bool offcon(const string &s1, const string &s2){6 string s3 = s1 + s1;7 cout<< s3 << endl;8 cout<< s2 << endl;9 cout<< s3.find(
阅读全文