- 博客(39)
- 收藏
- 关注
原创 在一个大串中查找和另外一个字符串是anagram的子串
在一个大串中查找和另外一个字符串是anagram的子串。比如,GetAnagram("abcdbcsdaqdbahs'', "scdcb'') ==> "cdbcs''。思路:用统计字符的方法来做。当然也可以用质数方法来做。#include #include #include #include using namespace std;int GetAna(const s
2013-08-22 21:30:40
1034
原创 二维数组中的最长递减子序列
给定一个如下的二维数组a[][]1 3 5 7 42 1 8 6 54 0 -1 -2 6求其中的最长递减子序列:7, 5, 3, 1, 0, -1, -2,长度为7。子序列只能朝向上下左右四个方向,不能朝对角线方向。思路:该题一看感觉可以用动态规划做,但是下标不确定从哪里开始算起,因为有上下左右四个方向,没有办法顺序计算。只有用
2013-08-18 21:37:31
1770
2
原创 单调队列
网上很多讲单调队列的资料,但是感觉讲的不是很清楚,大多都是只讲了思路,没有用实际的例子来阐述单调队列。单调队列,顾名思义是指队列内的元素是有序的,队头为当前的最大值(单调递减队列)或最小值(单调递增序列),以单调递减队列为例来看队列的入队和出队操作:1、入队: 如果当前元素要进队,把当前元素和队尾元素比较,如果当前元素小于队尾元素,那么当前元素直接进队,如果当前元素大于队尾元素
2013-08-16 23:01:42
1089
原创 递归求排列和组合(无重复和有重复)
给定一个大小为n的数组,输出所有全排列。1、数组中无重复元素:从前到后,依次将数组中的元素放置在输出数组中,若放完就输出,然后递归的改变元素的位置,直到输出所有的全排列。递归中使用一个标记数组来记录某个元素是否已经被放置过。2、数组中有重复元素:这个和1比较类似,区别在于用一个标记数组记录某个元素的次数,每放置一次就减一。问题1的代码如下:void PermRecur(vector
2013-08-15 09:17:47
1072
原创 CI8.4--求一个串的全排列
求一个串的全排列。思路:全排列实际上就是前后元素不断交换得到的结果。#include #include using namespace std;void Perm(vector& ivec, int begin){ if (begin == ivec.size()) { for (int i = 0; i < ivec.size(); ++i) cout <<
2013-08-14 15:11:43
555
原创 CI8.8--八皇后问题
八皇后问题。思路:这是个经典的递归问题。八皇后问题不允许任意两个皇后在同一行、同一列以及同一对角线。因为不允许同一列,我们只需要一个一维数组保存第i行皇后所在的列即可,例如c[r]表示第r行皇后所在的列。设任意两行r1, r2,不满足的条件的情况有:c[r1] == c[r2],c[r1] - c[r2] == r1 - r2,c[r1] - c[r2] == r2 - r1。从第0行开始
2013-08-14 15:01:04
703
原创 CI8.7--硬币组合问题
给定无限个面值为25分、10分、5分、1分的硬币,计算可以组成n分的组合方式的数目。思路:这是一个递归问题。例如n=100,我们先考虑最大的25分硬币。先取0个25分硬币,然后递归去组成100分;接着取1个25分硬币,然后递归去组成75分;接着再取2个25分硬币,然后递归去组成50分,等等。每次取了25分后,再按着相同的思路取10分、5分、1分。#include using name
2013-08-14 11:46:51
648
原创 CI8.5--有效括号组合问题
输出n对括号的所有有效组合。思路:运用递归的思想。只要左括号没有用完,总可以插入左括号;当已插入的左括号数目大于右括号,那么就可以插入右括号。我们只要记录左右括号剩余的数目,然后递归即可。递归终止条件有两个:当左括号剩余数小于0或者左括号剩余数大于右括号剩余数,此时为无效状态;当左右括号剩余数都为0,此时输出结果。#include #include using namespace
2013-08-14 10:53:54
852
原创 CI8.3--输出全部子集
输出一个集合a[1~n]的全部子集。思路:这是全组合问题。首先解决n个元素里取k个元素,然后循环调用即可。用递归解决。从后往前扫描,a[n]有两种情况:被选中;没被选中。如果被选中,子问题是从a[1~n-1]中选k-1个元素;如果没被选中,子问题是从a[1~n-1]中选k个元素。递归的终止条件是k==1。#include #include using namespace std
2013-08-14 10:10:11
651
原创 CI8.2--矩阵行走问题
1、一个m*n的矩阵a[][],机器人从左上角走到右下角,只能朝右或朝下走,输出所有路径。2、如果矩阵有的格子可以走,有的格子不可以走,输出所有路径。(a[i][j]==1表示可以走,a[i][j]==0表示不可以走)思路:典型的递归算法。问题1直接用深搜的思想。问题2在问题1的基础上加个判断条件即可。#include #include using namespace std;
2013-08-13 10:46:34
1274
原创 图的相关算法
图的基础相关算法有BFS,DFS,拓扑排序, 强连通分支,kruskal,prim,Bellman-Ford,Dijkstra。这些算法思想不难,就是代码容易忘记,所以将代码写在这里,以备复习。本文的代码都用邻接表结构。图的邻接表结构定义:struct Edge{ int id; //节点对应的id Edge* pNext;};struct Vertex{ int id;
2013-08-12 10:05:29
974
原创 最多连续数的子集
给一个整数数组a[], 找到其中包含最多连续数的子集,比如给:15, 7, 12, 6, 14, 13, 9, 11,则返回: 5:[11, 12, 13, 14, 15] 。最简单的方法是sort然后scan一遍,但是要 o(nlgn) , 有什么 O(n) 的方法吗?思路:网上有人用map来做,个人觉得用map的复杂度还是O(nlgn)。并查集可以做到O(n),但网上一
2013-08-08 14:03:21
1322
原创 CI20.12--最大子矩阵和问题
给定一个N*N的矩阵,计算最大子矩阵和。思路:最大子段和问题可以用动态规划在O(n)内解决,该题可以借助最大子段和的解法来做。我们考虑第i行到第j行的子矩阵,可以将i ~ j行的矩阵合并为一个一维数组,即把每列对应的数相加,那么这个一维数组的最大子段和就是原子矩阵的最大和。我们用一个二维数组p来保存矩阵的部分和,p[i][j]表示左上角是(1, 1),(下标从1开始), 右下角
2013-07-29 14:56:19
1508
原创 CI20.9--中位数问题
随机生成一些数,写一个程序找到这些数的中位数,并且当新的数生成的时候能够维护中位数。思路:直观的思路是排序或者用划分的思路找中位数,但是这些都是在数组固定的情况下,现在的情况是随时可能有新的数产生。1、可以用一个足够大的数组来维护这些数,然后每产生一个数就将它插入到数组中并保持有序,这样插入一个数的复杂度为O(n),取中位数的复杂度为O(1)。2、可以用一个堆来位数这些数,插入一个
2013-07-27 15:25:10
750
原创 CI20.8--多模式串匹配问题
给定一个目标串串T和若干个模式串P,设计一个算法去匹配每一个模式串。思路:多模式串匹配问题(设m为目标串的长度,n为模式串的平均长度)。可以用后缀trie树,时间复杂度为O(m^2 + kn)。利用AC自动机的时间复杂度为O(m + kn + z)(其中z为T中出现的模式串个数)。还可以用后缀树,后缀树的方法比较复杂,这里不做介绍。1、后缀trie树#include #inclu
2013-07-25 22:59:57
804
原创 CI20.6--求前K个数
描述一个算法,在十亿个(n)数中找出前一百万(k)大的数字。假设内存里可以放下十亿个数。思路:1、直接排序,然后输出前一百万个数,时间复杂度为O(n*logn)。2、维护一个大小为一百万的大顶推,然后遍历完十亿个数,输出大顶推的数即可,时间复杂度为O(n*logk)。该思路适合大数据,尤其是内存放不下所有数据的时候。3、利用快排的思想进行划分,一次划分后设主元的位置为index,如
2013-07-24 15:26:24
554
原创 CI20.4--计算0~n之间某个数出现的次数
实现一个方法,计算0~n之间2的出现次数。思路:有个类似题在编程之美和剑指offer上都出现过,是求1的个数。以12306这个数为例,首先我们看千位,千位上2的出现次数有:2000~2999、12000~12306,一共是1 * 1000 + 307;百位上2的出现次数有:200~299、1200~1299、2200~2299、...、12200~12299,一共是13 * 100;十位上
2013-07-23 14:23:40
732
原创 CI20.3--n个数里随机选m个,要求概率相等
实现一个方法,随机从一个大小为n的数组中选取m个数。要求每个元素被选中的概率相等。思路:这个题的思路和20.2的一样,只不过是选取m个。#include #include using namespace std;void Swap(int& a, int& b){ int temp = a; a = b; b = temp;}void RandomShuffle(
2013-07-23 11:08:11
1716
原创 CI20.2--洗牌算法
实现一个方法,对一副牌(52张)进行洗牌,要求洗出的52!组合是的等概率的,即每种组合的概率为1/52!,假设已经有一个完美的随机数生成器。思路:思路比较直观,第一次从52张牌中随机取一张出来,概率为1/52;第二次从剩下的51张随机取一张出来,概率为1/51;以此类推最终的概率就是1/52!。接下来是如何用代码实现,当选中一张牌之后,在下次选择的时候就不能让这张牌再参与选择,这个怎么实现
2013-07-22 11:46:59
811
原创 CI20.1--不用运算符做加法
实现一个函数求两个数的和。不可以用+或其他运算符号。思路:直观的思路是通过位运算来做加法。第一步:先不考虑进位,将两个数通过异或可以求得对应位的和;第二步:考虑进位,将两个数通过与运算可以求得哪些位有进位,然后将该结果左移一位,再和第一步中的结果进行异或,一直迭代制导进位的结果为0。#include using namespace std;int AddBit(int a, in
2013-07-22 10:32:00
712
原创 CI19.11-和为定值的数对
给定一个整型数组a[]和一个数sum,设计一个算法找到数组中所有的整数对(a[i], a[j]),其中a[i] + a[j] == sum。思路:可以用bitmap或者哈希来做,这样可以达到O(n)的复杂度。遍历一次数组,将bitmap[a[i]]的值置为1,然后再去检查bitmap[sum - a[i]]的值是否为1,这样就找到满足条件的整数对。如果数组中有重复数字且整数对中的数字不能重
2013-07-20 15:02:18
593
原创 CI19.10-利用rand5实现rand7
给定一个能生成1~5的随机生成器rand5(),怎么利用这个随机生成器去随机生成1~7的数字。思路:rand5()只生成1次肯定实现不了,所以可以考虑让rand5()生成两次,将两次的值组合来得到1~7的数字。rand5()生成两次的值的组合一共有25种组合,我们可以定义num = 5 * (rand() - 1) + rand5(),那么num的范围是[1, 25],我们可以把[1, 2
2013-07-20 14:35:51
606
原创 CI19.7-最大连续子段和
给定一个整型数组a[],计算最大连续子段和。例子:输入:(2, -8, 3, -2, 4, -10)输出:5 连续子段为(3, -2, 4)思路:典型的动态规划问题。对于DP,我们要先找到状态,然后再找到递推关系。定义d[i]为以a[i]结尾的最大连续子段和,那么递推关系为:如果d[i - 1] > 0,d[i] = d[i - 1] + a[i];否则d[i] = a[i]。
2013-07-20 14:05:59
587
原创 Coding Interview 19.5
(原题不说了,这里给出扩展的问题)给定两个长度相等的字符串A和B,输出两个值n和m。如果A[i] == B[i],则n加1;如果A[i] == B[j] (i != j),则m加1。思路:思路比较直观。用一个大小为256的bool数组表示A中字符的出现。#include #include #include using namespace std;void Compare(
2013-07-19 17:03:01
478
原创 CI19.4-不用条件语句和比较操作符求两个数的较大值
实现一个方法求两个数中的较大值,但不可以用if-else或其他比较操作符。思路:给定两个数a和b,最直观的思路就是看a - b和0的关系,但不允许用比较操作符。可以注意到,当a > b的时候,a - b的结果最高位为0,否则为1。我们另k为a - b的最高位的值,那么最大值就等于a - k*(a - b)。#include using namespace std;int Max(
2013-07-19 16:38:05
630
原创 CI19.3-n的阶乘末尾0的个数
实现一个算法,计算n的阶乘末尾有多少个0。思路:如果先计算n!,然后再计算末尾0的个数,这种方法不可取,因为n!随时可能溢出。阶乘末尾有0,肯定是2和5相乘而得。所以我们只需要计算因子2和因子5的对数。可以发现因子2的出现次数要大于因子5的出现次数,所以只计算因子5的个数即可。5!, 包含1*5, 1个510!, 包含1*5,2*5, 2个515!, 包含1*5,2*5,
2013-07-19 16:27:59
644
原创 CI19.1-原地交换两个数
实现一个函数原地交换两个数,且不能用辅助空间。思路:经典问题。void swap(int& a, int& b){ a = b - a; b = b - a; a = b + a;}void swap(int& a, int& b){ a = a ^ b; b = a ^ b; a = a ^ b;}如果参数是两个相同的数,则不可以调用以上两个形式
2013-07-19 15:56:44
646
原创 CI9.2-字符串排序
给一个字符串数组排序,排序规则是同构字符串挨在一起。思路:重写sort函数的比较函数,然后调用sort函数即可。#include #include #include #include using namespace std;bool cmp(string s1, string s2){ sort(&s1[0], &s1[0] + s1.size()); sort(&s
2013-07-18 23:24:30
449
原创 CI 9.7-叠罗汉
给定N个人的身高和体重,然后叠罗汉。规则是:每个人踩在另一个人的肩膀上,上面人的身高和体重都要低于下面的人。实现一个方法计算N个人最多可以叠多少人。例子:输入(height, weight):(65, 100) (70, 150) (56, 90) (75, 190) (60, 95) (68, 110)输出:6 (从上到下是:(56, 90) (60,95) (65,100) (
2013-07-18 23:07:57
876
原创 CI9.6-在特殊的矩阵中找给定的数
给定一个整数的二维数组,其中每行从左到右升序,每列从上到下递增。实现一个方法返回给定数在数组中的下标。思路:可以顺序查找,但是这样就没有利用升序的条件。因为行列都是有序的,所以通过一次比较尽可能排除一行或一列。如果从数组左上角开始比较,若给定数大于左上角的数,那么无法确定剔除这一行还是这一列。如果从数组右上角比较,若给定数较大,则可以剔除这一行,若给定数较小,则可以剔除这一列。当然也可以从
2013-07-18 11:49:20
680
原创 CI9.5-特殊字符串数组的二分查找
给定一个有序字符串数组,其中字符串两边可能会插入若干个空串。实现一个方法找到给定串的下标。例子:输入:[ "at", "", "", "", "ball", "", "", "car", "", "", "dad", "", "" ],"ball"输出:4输入:[ "at", "", "", "", "ball", "", "", "car", "", "", "dad", "",
2013-07-18 11:22:17
702
原创 CI9.3-旋转数组查找给定值
给定一个旋转了任意次的有序数组A和一个数n,实现一个O(logn)的算法返回n在A中的下标,若没有返回-1。(假定原有序数组是递增的)例子:输入:A:15,16,19,20,25,1,3,4,5,7,10,14;n:5输出:8思路:有序数组旋转之后,前半部分仍是有序的,后半部分无序,仍然可以用二分的思想。如果a[mid] == n,结束。如果a[mid] > n,有两种
2013-07-17 10:58:56
609
原创 CI9.1-合并有序数组
给定两个有序数组A和B,其中A的空间足够存放A和B的所有元素。实现一个函数:将B合并到A中,并保持有序。思路:比较简单,类似于字符串中将空格替换成“20%”那个问题。从尾到头进行合并即可。#include using namespace std;void Merge(int a[], int n, int b[], int m){ int i = n - 1; int j
2013-07-16 21:18:58
480
原创 CI5.7-寻找丢失的数
一个整形数组A[1...n]包含0~n中的n个数,有一个数丢失。规定不可以通过A[i]获取对应的整数,可以使用的唯一的操作是fetch(i, j),该函数表示获得A[i]的第j个bit的值(即二进制形式中的第j个bit)。假定fetch(i, j)的操作是常数的,如何在O(n)的时间内找出丢失的整数。思路:从0到n一共n+1个整数,用N0表示这n+1个整数中最低有效位为0的整数个数,用N1
2013-07-16 20:58:26
581
原创 CI5.6-交换整数二进制形式中的奇数偶数位
写一个程序交换一个整数二进制形式中的奇数位和偶数位。(用尽可能少的操作)思路:设整数位n,将n和0x55555555进行与运算并左移一位记录偶数位;将n右移一位再和0x55555555进行与运算记录奇数位,然后进行或运算即可。#include #include using namespace std;int SwapBits(int n){ return ((n & 0x555
2013-07-16 17:26:30
587
原创 CI5.5-计算将整数A变为整数B需要改变的二进制位数
实现一个函数,计算将整数A变为整数B需要改变的二进制位数。例子:输入:31,14输出:2思路:将A和B异或,然后计算结果中1的个数。#include using namespace std;int CountOne(int c){ int res = 0; for (int i = 0; i < 32; ++i) { if (c & 1 == 1) ++
2013-07-16 16:57:24
655
原创 CI5.3-寻找特殊的最大、最小数
给定一个整数n,输出小于n的最大整数max和大于n的最小整数min,且n、max、min这三个数的二进制表示中1的个数相等。思路:最大整数max:从最低位开始找到第一个为0的位,记为bit0;从bit0位开始继续,找到第一个为1的位,记为bit1。将bit0置为1,将bit1置为0,得到的结果就是max。最小正数min:从最低位开始找到第一个为1的位,记为bit1;从bit1为开始继续
2013-07-16 15:19:09
653
原创 CI5.2-输出浮点数的二进制
给定一个以字符串形式表示的小数(例如:3.72),输出该数的二进制表示。如果该数不能精确地表示为二进制形式,输出“ERROR”。例子:输入:3.25输出:11.01思路:将小数分成两部分:整数部分和小数部分。整数部分很简单。小数部分想要转化为二进制,可以将小数乘以2的结果和1进行比较,如果大于等于1,该位为1并将结果减1;否则为0。如果小数部分的二进制位数超过某个长度,可以认为无法
2013-07-16 10:39:39
739
原创 CI5.1-二进制置位
给定两个32位的数,N和M,还有两个指示位的数,i和j。 写程序使得N中第i位到第j位的值与M中的相同(即:M变成N的子串且位于N的第i位和第j位之间)例子:输入: N = 10000000000, M = 10101, i = 2, j = 6输出: N = 10001010100思路:使用一个mask,该mask的j+1位到最高位都为1,i位到j位都为0,0位到i-
2013-07-15 18:43:31
885
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人