自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

  • 博客(153)
  • 收藏
  • 关注

原创 栈和队列的相互模拟

1.用两个栈实现队列记两个栈为s1和s2,操作要求:入队时,若s2不为空,则将s2中的所有元素逐个出栈并压入s1中,然后再将需要入队的元素压入s1出队时,若s1不为空,则将s1中的所有元素逐个出栈并压入s2中,然后将s2的栈顶元素出栈需要注意的是,在入队/出队操作前,需要保证已入队的所有元素均在其中一个栈内,而不能同时分布在两个栈上2.用两个队列实现栈记两个队列

2012-05-29 09:03:12 263

原创 程序内存分布

1.栈:存放局部变量、函数参数及函数中间状态等,具有数据结构中的栈的“先进后出”特性。调用某个函数时,将该函数的上述数据入栈,结束调用时出栈销毁,因此可以理解为什么局部变量和形参的生存周期与函数调用相关。栈的优点是分配空间速度快,缺点是可分配空间有限2.堆:存放动态分配(malloc、new)的对象(与数据结构中的堆无任何关系)。根据C的特性,堆中存放的对象将一直存在直至人为释放(free)或

2012-05-28 22:41:46 273

原创 内存分布

1.栈:存放局部变量、函数参数及函数中间状态等,具有数据结构中的栈的“先进后出”特性。调用某个函数时,将该函数的上述数据入栈,结束调用时出栈销毁,因此可以理解为什么局部变量和形参的生存周期与函数调用相关。栈的优点是分配空间速度快,缺点是可分配空间有限2.堆:存放动态分配(malloc、new)的对象(与数据结构中的堆无任何关系)。根据C的特性,堆中存放的对象将一直存在直至人为释放(free)或

2012-05-28 22:07:56 126

原创 找前K大的所有数

问题描述:注意和“找第K大的数”相区别方法1:可利用“找第K大的数”问题的解法,经过多次一趟排序,找出第K大的数,那么该数以及该数左边的所有数即所求的“前K大的所有数”(一趟排序的性质)方法2:利用一个大小为K的小顶堆进行辅助操作,具体方法为:将数组前K个元素建成一个小顶堆扫描数组剩下的N-K个元素,每次扫描一个并进行判断:若该元素大于(不包括等于)小顶堆的堆顶元素,则用该元素

2012-05-28 21:06:25 1609

原创 特殊矩阵运算

问题描述:假设矩阵存在某种特殊运算,要求对矩阵任意一个元素减1时,必须对其邻居(上下左右)中的一个同时减1。现给定一个矩阵,要求判断能否通过有限次特殊运算得到零矩阵思路:回溯法。枚举所有可进行特殊运算的位置并以此递归,若出现元素小于0的情况则进行回溯。不用每次判断零矩阵,只需要维护一个计数变量cnt,统计当前矩阵非零元素个数。每次进行特殊运算时,更新cnt的值代码(效率较低,应该可以进一步

2012-05-27 19:59:33 356

原创 将数组分成和相等的若干子数组

问题描述:对一个整数数组,将其分为k个子数组,使得各数组的和相等。求k的最大值思路:1.记数组a中的最大元素为max,a本身的和为sum,则m的值不会超过ceil(sum/max)。因为若m > ceil(sum, max),则max不可能被放到任何一个子数组中2.在1的基础上,记k为当前分割份数,k从ceil(sum, max)遍历至1,判断能否分成k个相等和子数组,具体判断方法为:

2012-05-27 18:39:30 1424 1

原创 质数环问题

问题描述:给定正整数n,要求将n个正整数1, 2, ..., n组成一个环,确保环中任意两个相邻元素之和为质数思路:回溯法。在枚举过程中进行回溯剪枝。另外,为确保不出现重复的环,令第一个元素为1代码:int isp(int k){ //判断k是否为质数 int ok = 1; for(int i = 2; i < sqrt(k); i++){ if(k%i == 0){

2012-05-27 15:12:55 1035 1

原创 八皇后问题

问题描述:在8×8的棋盘上放置8个皇后,确保她们互不攻击(皇后攻击范围为同行、同列以及同对角线)思路:首先可以确定在此问题的任意一个正确解里,8个皇后必然各占一行(不能同行),因此问题可以简化为:为每一行的皇后找到正确的对应列(列必然也是互异的)。若用穷举法(全排列)的话,共有8! = 40320种可能。在此基础上,我们使用回溯法减少不必要的枚举,具体为:每次放置一个皇后,若该皇后与之前放置的

2012-05-25 19:43:12 292

原创 子集和问题

问题描述:对给定集合A和整数K,求出A的所有和等于K的子集(可以包括其本身),如A = {10, 20, 30, 40, 50, 60}且K = 60,则满足条件的子集有{10, 20, 30}, {10, 50}, {20, 40}, {60}思路1:利用二进制法枚举子集,再找出满足条件的子集。此方法优点是思想简单,缺点是枚举本身效率不高代码:void process(int

2012-05-25 16:23:11 405

原创 枚举子集问题

问题描述:枚举给定集合的所有子集,包括只含一个元素的集合以及给定集合本身。当集合中出现值相同的元素时,根据不同性质可将子集分为:允许重复包含相同值的元素不允许重复包含相同值的元素思路:利用二进制的“开关”特性枚举,具体为:假设给定集合A大小为n,则想象A = {a[0], a[1], ..., a[n-1]}的每个元素对应一个开关位(0或1),0表示不出现,1表示出现。

2012-05-25 15:45:07 674

原创 字符串全排列

字符串全排列的两个例子:1.abc的全排列有:abcacbbacbcacbacab2.aab的全排列有:aabababaa思路:使用回溯法。对于abc,a和a交换仍是abc;a和b交换可得bac;a和c交换可得cba,至此第一个字母的遍历结束。从上述结果中进行第二个字母的遍历:对于abc,b和b交换仍是abc,b和c交换可得acb;对于bac

2012-05-23 21:21:46 426

原创 单链表逆输出

实际上递归实现单链表逆输出不一定优于辅助堆栈或辅助数组,只是可读性更强代码:typedef struct node{ int data; struct node * next;} Node;void print(Node * p){ assert(p != NULL); if(p->next != NULL) //递归,先输出后继结点 print(p->n

2012-05-23 14:36:52 259

原创 递归实现单链表逆输出

实际上递归实现单链表逆输出不一定优于辅助堆栈或辅助数组,只是可读性更强代码:typedef struct node{ int data; struct node * next;} Node;void print(Node * p){ assert(p != NULL); if(p->next != NULL) //递归,先输出后继结点 print(p->nex

2012-05-23 14:33:09 351

原创 任意多次交换两数组元素使得两数组之和的差值最小

思想:注意两数组长度不一定相同。现只能想到穷举法(时间复杂度大约为O(n^3)):记当前两数组之和的差值为abs(diff),其中diff=sum_A-sum_B,遍历所有组合(a[i], b[j]),察看abs(diff-2*(a[i]-b[j]))与abs(diff)的大小,若前者更小,则更新diff -= 2*(a[i]-b[j])并swap(a[i], b[j]);若找不到这样的组合,则当

2012-05-23 09:46:32 552

原创 任意次数交换两数组元素使得两数组之和的差值最小

思想:注意两数组长度不一定相同。现只能想到穷举法(时间复杂度大约为O(n^3)):假设当前两数组之和的差值为abs(diff),其中diff=sum_A-sum_B,遍历所有组合(a[i], b[j]),察看abs(diff-2*(a[i]-b[j]))与abs(diff)的大小,若前者更小,则更新diff -= 2*(a[i]-b[j])并swap(a[i], b[j]);若找不到这样的组合,则

2012-05-23 09:39:28 229

原创 常用排序算法总结

排序方法平均时间最坏情况辅助存储稳定性备注冒泡排序O(n^2)O(n^2)O(1)稳定 插入排序O(n^2)O(n^2)O(1)稳定 选择排序O(n^2)O(n^2)O(1)不稳定 快速排序O(n*logn)O(n^2)O(logn) ~ O(n)不稳定

2012-05-22 10:20:40 279

原创 选择排序(selection sort)

选择排序的时间复杂度为O(n^2)算法思想:每次遍历当前未排序部分,记录其中最大元素的下标,遍历完成后,将该元素与未排序部分的最后一个元素交换;每次遍历后未排序部分的长度减1代码如下:void swap(int * a, int * b){ assert(a != NULL); assert(b != NULL); if(a != b){ *a ^= *b; *

2012-05-21 22:56:33 204

原创 冒泡排序(bubble sort)

冒泡排序的时间复杂度为O(n^2),是一种原地排序,是一种稳定排序冒泡排序的思想是:每趟冒泡将序列中未排序部分的相邻两元素比较交换,确保将其中的最大元素“沉底”,未排序部分的长度每趟减1,第K趟冒泡可将原序列的第K大元素“沉底”冒泡排序算法思想简单,但效率很低。相比于直接插入排序,虽然时间复杂度均为O(n^2),但冒泡排序的“交换”次数要多很多,因此直接插入排序要优于冒泡排序代

2012-05-21 22:35:49 201

原创 求和为K的所有连续正整数序列

思路:维护两个指针p和q,分别指向当前序列和sum所对应序列的起点和终点。若sum N则p右移且sum减小;若sum == N则输出p、q所指序列,然后q继续右移,如此循环。程序中止条件为q > (N+1)/2,原因是:若序列存在一个或多个大于等于(N+1)/2的元素,则其和必然大于N代码:void process(int n){ assert(n > 0); int p

2012-05-19 19:52:42 413

原创 判断单链表存储的回文

思路:维护两个指针slow和fast,其中fast每次步进2,slow每次步进1,并且slow在步进过程中对单链表逆置。当fast遍历至尾结点时,slow恰好在链表中点位置,而链表前半段已全部被逆置。此时维护两个指针从中心出发向两头遍历判断回文。需要注意的一点:回文有奇偶两种长度,在fast步进过程中计数判断是哪种,据此设置中心指针的初始位置代码:typedef struct

2012-05-18 21:56:55 505

原创 找单链表的倒数第K个结点

思路:只需遍历一次单链表,维护两个指针p和q,初始时均指向头结点。p先移动k-1步,然后p和q同时移动直至p指向尾结点,此时q所指的结点即倒数第K个结点代码:typedef struct node{ int data; struct node * next;} Node;Node * process(Node * L, int k){ assert(L != NUL

2012-05-18 19:18:50 934

原创 最长回文子串

问题描述:求一给定字符串的最长回文子串,如google的最长回文子串是goog思路:遍历所有可能的回文串中心,维护两个指针p、q从中心向两边移动直至回文边界,统计该回文长度并与当前最长回文长度比较、更新。注意回文有奇数长度如aba和偶数长度abba两种情况代码:void process(char * s){ assert(s != NULL); int n = str

2012-05-18 19:04:10 221

原创 KMP算法

算法概述KMP算法的基本思想是:通过分析模式串P,得出一个next[]数组,以指示:当源串字符S[i]与P[j]不匹配时,下一步应比较S[i]和P[next[j]],若仍不匹配,则比较S[i]和P[next[next[j]]]...如此循环。因此在整个过程中,指向S的指针i是始终不回溯的,指向P的指针j会根据当前匹配状况按next[]数组的值回溯。假设S和P的长度分别为n和m,则KMP算法的时

2012-05-16 18:12:32 172

原创 判断单链表是否有环

单链表有环是指原来的尾指针指向了该链表中的任意一个结点(不一定是头结点,也就是说不一定是循环链表)思路:设置两个指针fast和slow,都从链表头结点出发。fast每次步进2,slow每次步进1,因此fast相对于slow的步进速度是1。若有环则二者一定会重合,若无环则fast最先为NULL代码如下:int process(Node * L){ assert(L != N

2012-05-16 09:36:58 162

原创 调整数组顺序使奇数在偶数前面

思路:双指针p和q,p指向数组头部向后遍历直到遇到偶数停止,q指向数组尾部向前遍历直到到奇数停止,交换p和q指向的元素,然后p、q继续按上述规则移动;程序终止条件是p == q(无需再对p、q作防越界判断)类似的题有:调节字符串使小写字母排在大写字母前面代码如下:void process(int a[], int n){ assert(a != NULL); asser

2012-05-15 23:07:37 146

原创 最短长度的珠子

题目要求和分析见题库这儿只讲一点:p1和p2停下,得到序列,和当前最短序列比较完毕后,class为k-1(k为颜色数)。此时要保持class和color[],p1和p2重复那两个步骤,直至class再次等于k,会再次得到序列,再去和当前最短序列比较,如此循环。程序中止条件是p2越过最后一个元素循环至头一个元素(珠子是首尾相接的)代码如下:void shortest_chai

2012-05-15 20:40:07 208

原创 判断数组中是否存在两数,其和等于给定值

思路:若数组无序,则先将数组排为升序。设给定值为sum,维护两个指针p和q,p指向数组头部,q指向数组尾部。若*p+*q  sum,则q--;若*p+*q == sum,则存在这两个数;程序中止条件为p == q(因此避免了*p+*q == sum且p == q的情况)代码如下:int process(int a[], int n, int sum){ assert(a !=

2012-05-15 16:12:38 556

原创 利用bit数组进行桶排序

本机器上int类型大小为4字节,即32bit,因此使用bit数组能使桶排序的空间开销缩小为原来的1/32bit数组可用于hash法去除重复元素或统计出现次数代码如下:#define SHIFT sizeof(int)*8 //32bitint main(){ int bit_array[100] = {0}; //此bit数组支持的整数范围为1~3199 int

2012-05-15 15:42:47 319

原创 判断一个数是不是某个自然数的平方

基本思路是二分查找,只是判断标准变为x^2 ?= key改进思路是缩小二分查找的起始区间,步骤如下:设被查找数为N,令A = 1,B = N每次令 A *= 2, B /= 2,直到A >= B停止此时,若A == B,则N是A的平方;若A > B,则二分查找的初始区间为[B, A]若二分查找失败,则N不是某个自然数的平方改进思路的证明:假设存在K,使得2^K >= N/(2^

2012-05-14 20:58:17 915

原创 大数乘法

这里的大数是指:超过计算机变量(包括long long)表示范围的数因此我们考虑用字符串保存两个乘数以及结果,按位相乘需要注意两点:记两乘数分别为X和Y,其中X有m位,Y有n位,则Z=X*Y可能有m+n位或m+n-1位。如10*10=100, 99*99=9801。因此计算结果可能存在1位前置0,需要判断处理每一轮相乘完毕后,最后的进位(cf)记得加到被乘数的对应位上

2012-05-10 15:19:07 614

原创 单链表快排

在单链表上实现快排,需要考虑以下几个因素:单链表存取随机结点需要从头遍历指针单向,取前驱结点需要从头遍历不能像数组那样以下标判断越界因此,我们使用一趟排序中的策略三,其好处是:只要维护足够多(实际上也并不多)的指针,就能只遍历一次即完成一趟排序但和数组快排不同的是:为了方便,不使用三数中值分割法选取pivot(需要遍历一次链表),而直接使用当前子链表的第一个结点作为

2012-05-09 17:10:36 1100

原创 C中的断言(assert)

assert格式assert是C语言中的一个宏定义(需要包含assert.h),基本格式为assert(bool expression);当bool expression的值为True,则assert不做任何动作;否则会在stderr中输出一条错误信息,其格式如下:Assertion failed: [expression], file [filename], line [nnn]as

2012-05-08 22:09:22 597

原创 C中的断言(assert)

assert格式assert是C语言中的一个宏定义,基本格式为assert(bool expression);当bool expression的值为True,则assert不做任何动作;否则会在stderr中输出一条错误信息,其格式如下:Assertion failed: [expression], file [filename], line [nnn]assert的用法在

2012-05-08 21:45:31 221

原创 分治法+一趟排序求数组中第K大的元素

算法思想见题库代码如下:void swap(int * a, int * b){ assert(a != NULL); assert(b != NULL); if(a != b){ *a ^= *b; *b ^= *a; *a ^= *b; }}int partition(int a[], int left, int right){ assert(a !=

2012-05-08 16:43:11 740

原创 欧几里德算法(辗转相除法)求两数的最大公因数

欧几里德原理a,b为两个正整数,记gcd(a, b)表示a和b的最大公因数(a>b),则必然有:gcd(a, b) = gcd(b, a%b),其中a%b不为0证明如下:1.a可以表示为a = k*b+r,即r = a%b = a-k*b2.记d = gcd(a, b),即有:a%d = 0且b%d = 03.根据步骤2,必然有:r%d = (a-k*b)%d = a%d -

2012-05-08 16:36:00 300

原创 最大子序列和问题

问题描述:给定一个整数序列(可能有负数),求一子序列(记为L‘)使得该子序列所有元素之和最大。例:给定序列-2,11,-4,13,-5,-2,则最大子序列和为20(11,-4,13)方法一:遍历穷举——O(n^2)略方法二:分治递归——O(n*logn)思路:将输入序列L分为左右两个子序列L1和L2,则L’只可能以下面三种情况出现:L‘完全在L1中,则L

2012-05-08 10:52:32 147

原创 利用位异或(^)进行数值交换

首先,位异或具有如下性质:a^b^b == a;a^b^a == b;因此,我们可以利用位异或可以在不引入第三变量的情况下进行数值交换,代码如下:a = a^b;b = a^b;a = a^b;也可以写成a ^= b;b ^= a;a ^= b;但是应注意,当swap的两个参数是同一变量时,用位异或会出现错误,如:void swap(int

2012-05-07 21:00:34 234

原创 关于字符串

一些基本概念用字符数组保存这么一个字符串:char str[] = "hello world";然后我们应该知道,1.数组的大小是12(字符串字符个数+1),最后一个元素为'\0',用于标记字符串的结束。'\0'不是数字0,它是非打印字符,其ASCII码值为02.若使用如下定义:char str[100] = "hello world";则多余元素的值均默认为'\0'3.使

2012-05-02 21:23:20 131

原创 函数指针

什么是函数指针就像某一变量的地址可以存储在相应的指针变量中一样,指向函数的指针中保存着函数代码起始处的地址函数指针的声明当声明一个函数指针时,必须声明它指向的函数类型。要指定函数类型,就要指出函数的返回类型和参数列表,如:void (* pf)(int, int); //pf是一个函数指针,它指向的函数类型为:返回值为void,参数列表为(int, int)函

2012-05-02 16:16:39 122

原创 结构,联合和枚举

结构结构的声明格式如下:struct id{ char first[10]; char last[10]; int age;}; //别忘了右花括号后面的分号1.和数组类似的是,结构变量可在定义时初始化,如:struct id tae = { "aaa", "bbb", 10 };同样的,这种初始化只能在定义时进行。若在定义之后的地方进行,编译器会报错;但可用匿

2012-05-02 10:06:15 432

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除