算法
文章平均质量分 52
小僧_
这个作者很懒,什么都没留下…
展开
-
统计一行字符中有多少个单词
题目:如何统计一行字符中有多少个单词。 思路分析: (1)单词的个数可以由空格出现的次数决定,连续的若干个空格作为出现一次空格,一行开头的空格不统计在内。 (2)如果测出某一字符为非空格,而它的前面的字符是空格,则表示“新的单词开始了“,此时使单词数count累加1。 (3)如果当前字符为非空格,而其前面的字符也是非空格,则意味着仍然是原来那个单词的继续,count不应再累加1。 (4)添原创 2016-06-18 19:43:45 · 3058 阅读 · 0 评论 -
简单选择排序
算法思想: 简单选择排序的基本原理如下:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换;接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换;重复该过程,直到进行比较的记录只有一个时为止。实现过程为: (1)将整个记录序列划分为有序区和无序区,初始时,有序区为空,无序区含有待排序的所有记录。 (2)在无序区中选原创 2016-05-25 18:46:52 · 2310 阅读 · 0 评论 -
堆排序
(1)堆排序(heap sort)是简单选择排序的一种改进,改进的着眼点是:如何减少关键码的比较次数。简单选择排序在一趟排序中仅选出最小关键码,没有把一趟比较结果保存下来,因而记录的比较次数较多。堆排序在选出最小关键码的同时,也找出较小关键码,减少了在后面的选择中的比较次数,从而提高了整个排序的效率。堆排序为不稳定排序,不适合记录较少的排序。(2)堆是一种特殊的树形数据结构,其每个节点都有一个值,通原创 2016-05-26 20:01:05 · 562 阅读 · 0 评论 -
排序算法稳定性
1、什么是排序算法的稳定性 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。2、排序算法稳定性的判断方法 <1> 对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性; <2> 对于稳定的排序算法,必须对算法进行原创 2016-05-26 21:35:10 · 453 阅读 · 0 评论 -
常用排序算法的时间复杂度和空间复杂度
总结: (1)当排序记录个数n较大,关键码分布较随机,且对稳定性不作要求时,采用快速排序为宜。 (2)当待排序记录个数n较大,内存空间允许,且要求稳定排序时,采用归并排序。 (3)当待排序记录个数n较大,关键码分布可能出现正序或逆序的情况,且对稳定性不作要求时,采用堆排序或归并排序。 (4)当待排序记录个数n较大,而只要找出最小的前几个记录,采用堆排序或简单选择排序。 (5)当待排序记录个原创 2016-05-27 13:06:59 · 10196 阅读 · 3 评论 -
折半插入排序
1、基本概念 折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。2、算法思想 在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为原创 2016-05-27 14:35:46 · 377 阅读 · 0 评论 -
基数排序
编程论到极致,核心非代码,即思想。 所以,真正的编程高手同时是思想独到及富有智慧(注意与聪明区别)的人。 每一个算法都是一种智慧的凝聚或萃取,值得我们学习从而提高自己,开拓思路,更重要的是转换思维角度。 其实,我们大多数人都活在“默认状态”下。没有发觉自己的独特可设置选项—–思想。 言归正传(呵呵!恢复默认状态),以下学习基数排序。【1】基数排序 以前研究的各种排序算法,都是通过比较数据大转载 2016-05-27 18:59:08 · 350 阅读 · 0 评论 -
n个元素的全排列(递归+去重)
排列组合是算法常用的基本工具,如何在c语言中实现排列组合呢?思路如下:本文主要探讨递归实现,由于递归将问题逐级分解,因此相对比较容易理解,但是需要消耗大量的栈空间,如果线程栈空间不够,那么就运行不下去了,而且函数调用开销也比较大。(1) 全排列: 全排列表示把集合中元素的所有按照一定的顺序排列起来,使用P(n, n) = n!表示n个元素全排列的个数(假设集合中没有重复元素)。例如:{1, 2,原创 2016-06-16 13:10:37 · 18584 阅读 · 2 评论 -
剑指offer - 面试题28:字符串的排列(递归+去重)
题目:输入一个字符串,打印出该字符串中字符的所有排列。 例如:输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。 但是,还应当考虑字符串中是否有重复元素,如“112”的全排列只有“112、121、211”三种情况;思路分析: (1)把一个字符串看成由两部分组成:第一部分为它的第一个字符,第二部分是后面的所有字符。 (2)求整个字原创 2016-06-14 15:06:13 · 1146 阅读 · 0 评论 -
希尔排序
希尔排序(shell sort)是对直接插入排序的一种改进,改进的着眼点是:(1)若待排序记录按关键码基本有序,直接插入排序的效率很高;(2)由于直接插入排序算法简单,则在待排序记录个数较少时效率也很高。算法思想: 希尔排序也称为“缩小增量排序”。它的基本思想是:首先将待排序的元素分成多个子序列,使得每个子序列的元素个数相对较少,对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序后”,再原创 2016-05-25 15:48:09 · 342 阅读 · 0 评论 -
直接插入排序
算法思想: 对于给定的一组记录,初始时假设第一个记录自成一个有序序列,其余的记录为无序序列;接着从第二个记录开始,按照记录的大小依次将当前处理的记录插入到其之前的有序序列中,直至最后一个记录插入到有序序列中为止。代码很简单,详见代码注释:#include <iostream>void insertSort(int arr[], int len){ int i,j,temp; fo原创 2016-05-25 10:32:11 · 403 阅读 · 1 评论 -
找出一个字符串中第一个只出现一次的字符
题目:在字符串中找出第一个只出现一次的字符。如输入 “abaccdeff”,则输出b。 思路分析: (1)由于题目与字符出现的次数相关,那么是不是可以统计每个字符在该字符串中出现的次数?要达到这个目的,我们需要一个数据容器来存放每个字符出现的次数。在这个容器中可以根据字符来查找它出现的次数,也就是说这个容器的作用是把一个字符映射成一个数字。在常用的数据容器中,哈希表正是这个用途。 (2)我们可原创 2016-06-18 17:28:26 · 3549 阅读 · 0 评论 -
字符串逆序(二)
二、按单词逆序 给定一个字符串,按单词将字符串逆序。例如,给定 ” I am a student “,则输出是 “student a am I “,为了简化问题,字符串中不包含标点符号。一共分两个步骤,第一步先按单词逆序得 ” I ma a tneduts”,第二步整个句子逆序得到 “student a am I “。#include <iostream>using namespace std;原创 2016-06-18 14:06:46 · 497 阅读 · 0 评论 -
字符串逆序(一)
一、普通的字符串逆序 例如,给定一个字符串 s,将 s 中的字符顺序颠倒过来,如 s = “abcd”,逆序后变成 “dcba”。可以采用多种方法对字符串进行逆序,以下将对其中的一些方法进行分析。 (1)直接分配一个与原字符串等长的字符数组,然后反向拷贝即可。 具体实现如下:#include <iostream>char *Reverse(char *s){ char *q = s;原创 2016-06-17 21:39:23 · 5535 阅读 · 0 评论 -
冒泡排序(单向)
算法思想: 冒泡排序顾名思义就是整个过程就像气泡一样往上升,单向冒泡排序的基本思想是(假设由小到大排序):对于给定的n个记录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换其位置,进行一轮比较和换位后,n个记录中的最大记录将位于第n位;然后对前(n - 1)个记录进行第二轮比较;重复该过程直到进行比较的记录只剩下一个时为止。#include <iostream>v原创 2016-05-23 16:37:03 · 573 阅读 · 0 评论 -
冒泡排序(双向)
基本算法思想: (1)双向冒泡排序是冒泡排序的一种优化,它的基本思想是首先将第一个记录的关键字和第二个记录的关键字进行比较,若为“逆序”,则将两个记录交换,然后比较第二个记录和第三个记录的关键字。依次类推,直至第n-1个记录的关键字和第n个记录的关键字比较过为止。这是第一趟冒泡排序,其结果是使得关键字最大的记录被安置到最后一个记录的位置上。 (2)第一趟排序之后进行第二趟冒泡排序,将第n-2个记原创 2016-05-23 21:50:12 · 2813 阅读 · 0 评论 -
快速排序
算法思想: (1)快速排序是一种非常高效的排序算法,它采用”分而治之”的思想,把大的拆分为小的,小的再拆分为更小的。其原理是:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前部分的所有记录均比后部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止。 (2)具体算法步骤: <1> 分解:将输入的序列 arr[m, … , n]划分成原创 2016-05-24 13:40:58 · 582 阅读 · 0 评论 -
归并排序(递归实现)
算法思想: (1)归并排序是利用递归与分治技术,将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列。其中“归”代表的是递归的意思,即递归地将数组折半地分离为单个数组。例如,数组[5,2,1,7]会先折半,分为[5,2]和[1,7]两个子数组,然后再折半将数组分离,分为[5],[2]和[1],[7]。“并”就是将分开的数据按照按照从小到大或原创 2016-05-24 21:12:05 · 761 阅读 · 0 评论 -
归并排序(非递归)
接着上篇文章归并排序(递归)来探讨下,归并排序的非递归实现。归并排序的非递归实现: (1)将两个相邻的有序序列归并成一个有序序列,我们称为“一次归并”。 (2)“一趟归并”,是多次执行“一次归并”的结果。在“一趟归并”中,除最后一个有序序列外,其他有序序列中记录的个数(称为序列长度)相同,用h表示。现在的任务是把若干个相邻的长度为h的有序序列和最后一个长度有可能小于h的有序序列进行两两归并,把结原创 2016-05-24 22:05:04 · 770 阅读 · 0 评论 -
n个元素的所有子集(递归+非递归 +不去重)
一、非递归方法 思路分析:n个元素的子集共有2^n个,其中包括空集。 (1)假设有3个元素{a, b, c},那么此时有 2^3 个子集,即8个子集。 (2)因为有8个子集,而且包括空集,注意7对应的二进制形式为111,并且二进制数刚好3位;所以(000 ~ 111)可分别对应一个子集,若该位为1,则表示该元素出现在子集中,若该位为0,则表示该元素不出现在子集中; (3)注意:001中的1在原创 2016-06-12 17:29:04 · 10504 阅读 · 1 评论 -
对n个数进行排序(空间复杂度O(1))
题目:如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1) ? 思路分析: (1)关键:哈希表,空间复杂度O(1)中1的含义(只要是常量就可以) (2)在数字范围有限制的情况下,只需要用一个数组记录每个数字出现次数就可以了。 (3)假定你的数字范围在0到65535范围之内,定义一个数组count[65536](这个空间是常量,和n无关,所以是O(1) ),初值全部为0。原创 2016-06-11 10:20:13 · 4592 阅读 · 0 评论 -
去除整型数组中的重复数字
题目:如何把一个整型数组中重复的数字去掉。 分析:首先通过快速排序对数组进行排序,然后对排好序的数组经过一次遍历,将其重复元素通过交换,最终达到删除重复元素的目的。总的时间复杂度为 O(nlogn),空间复杂度为O(1)。下面借助c语言类库中自带的快速排序算法qsort,来实现排序。具体实现如下:#include <iostream>int comp(const void *a, const vo原创 2016-06-27 20:12:57 · 8438 阅读 · 1 评论 -
数组中重复次数最多的数
题目:如何找出数组中重复次数最多的数。 方法一:以空间换时间,即hash法。可以定义一个数组 int count[MAX],并将其数组元素都初始化为0;然后对原数组array[ ]进行遍历,并执行 count[ array[ i ] ]++ 操作;最后在count数组中找到最大的数,该数在count数组中对应的下标,即为array数组中重复次数最多的数。具体实现如下:#include <iostr原创 2016-06-23 22:24:51 · 5179 阅读 · 0 评论 -
两个有序整型数组的交集
题目:如何计算两个有序整型数组的交集? 例如,两个含有 n 个元素的有序(非降序)整型数组 a 和 b(数组 a 和 b 中都没有重复元素),求出其共同元素。 int a[ ] = {1, 2, 3, 4, 5}; int b[ ] = {1, 3, 5, 7, 9}; 那么它们的交集为{1, 3, 5}。计算数组交集可以采用很多种方法,但数组的相对大小一般会影响算法的效率,所以需要根据两个原创 2016-06-23 19:24:53 · 1609 阅读 · 0 评论 -
如何在排序数组中,找出给定数字出现的次数
题目:如何在排序数组中,找出给定数字出现的次数?例如,数组{1, 2, 2, 2, 3} 中 2 的出现次数是3次。思路分析:本题有多种解法。如取出该特定值,然后循环遍历该数组,统计该特定值出现的次数;或者使用 hash 法,来统计该特定值出现的次数。本文主要讨论在二分查找的基础上来解决该问题。设数组 array 为递增序列,需要查找的元素为findData,为了求解给定数字出现的次数,可以分别寻找原创 2016-06-23 15:07:32 · 1253 阅读 · 0 评论 -
二分/折半查找(递归+非递归)
二分查找法也称为折半查找法,它的思想是每次都与序列的中间元素进行比较。二分查找的一个前提条件是数组是有序的,假设数组array为递增序列,findData为要查找的数,n为数组长度,首先将n个元素分成个数大致相同的两半,取array[n/2]与将要查找的值findData进行比较,如果findData等于array[n/2],则找到findData,算法终止;如果 findData < array[原创 2016-06-23 14:40:18 · 719 阅读 · 0 评论 -
用递归算法判断一个数组是否递增
本题要求使用递归算法,设数组为array,则递归数组满足以下条件。 (1)如果数组长度为1,则该数组为递增,返回true。 (2)如果数组长度为n(n >= 2),则先比较最后两个元素是否递增,如果最后两个元素递增,则再递归比较除去最后一个元素的前 n-1 个元素是否递增。具体实现如下:#include <iostream>bool IsIncrease(int arr[],int len){原创 2016-06-23 10:50:01 · 8260 阅读 · 2 评论 -
用一个for循环打印出一个二维数组
思路分析: int array[row][column]; 首先,二维数组在内存中默认情况下是行存储的,所以可以将二维数组array看成一个一维数组,i 标识该数组在一维数组中的位置,则array在二维数组中的行号和列号分别为 [ i / column] 和 [ i % column]。 例如,arr[2][3] = {1, 2, 3, 4, 5, 6}; 数组元素对应的下标为 0,原创 2016-06-23 09:50:54 · 7236 阅读 · 0 评论 -
递归实现数组求和
如果使用递归,则需要考虑如何进行递归执行的开始以及终止条件。 (1)首先,如果数组元素个数为0,那么和为0。 (2)如果数组元素个数为n,那么先求出前 n - 1 个元素之和,再加上 arr[n - 1] 即可。此时可以完成递归功能。具体实现如下:#include <iostream>int sum = 0;int GetSum(int arr[], int len){ if (le原创 2016-06-22 21:19:10 · 4467 阅读 · 0 评论 -
将数组的后面m个数移动为前面m个数
题目:如何将数组的后面m个数移动为前面m个数。 思路分析: 有n个整数,使前面各数后移m个位置,最后m个数变成最前面m个数。例如,有10个数的数组,即 n=10,它们的值分别是 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,如果取 m=5的话,经过位置调整后,变为 6, 7, 8, 9, 10, 1, 2, 3, 4, 5。 可以通过递归的方法实现调整: (1)将前 m个元素的原创 2016-06-18 21:50:15 · 2804 阅读 · 0 评论 -
找出数组中出现次数超过一半的数(时间复杂度O(n))
题目:如何在O(n)的时间复杂度内找出数组中出现次数超过了一半的数。 由于本题对时间复杂度有要求,所以可采用以下2种方法。方法一:每次取出两个不同的数,剩下的数字中重复出现的数字肯定比其他数字多,将规模缩小化。如果每次删除两个不同的数(不管包括不包括最高频数),那么在剩余的数字里,原最高频数出现的频率一样超过了50%,不断重复这个过程,最后剩下的将全是同样的数字,即最高频数。此算法避免了排序,时间原创 2016-06-24 13:27:01 · 9110 阅读 · 3 评论 -
判断数组中的数字是否连续相邻
一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现;0是例外,可以反复出现。设计一个算法,当从该数列中随意选取5个数值时,判断这5个数值是否连续相邻。需要注意以下4点: (1)5 个数值允许是乱序的,如 8 7 5 0 6。 (2)0 可以通配任意数值,如8 7 5 0 6 中的 0 可以通配 9 或者 4。 (3)0 可以多次出现。 (4)全0算连续,只有一个非原创 2016-06-24 20:35:57 · 8365 阅读 · 0 评论 -
如何判定数组是否存在重复元素
题目:假设数组 array 有 n 个元素,元素取值范围是 1~n,如何判定数组是否存在重复元素? 方法一:对数组进行排序(可以用效率比较高的排序算法,如快速排序、堆排序等),然后比较相邻的元素是否相同。时间复杂度为 O(nlogn),空间复杂度为O(1)。下面借助c语言类库中自带的快速排序算法qsort,来实现排序。#include <iostream>int comp(const void *原创 2016-06-27 16:44:16 · 9917 阅读 · 0 评论 -
找出数组中唯一的重复元素
题目:数组 arr[N],1 至 N 这 N - 1 个数存放在 arr[N] 中,其中某个数重复一次,写一个函数,找出重复的数字。要求每个数组元素只能访问一次,不用辅助存储空间。 分析:由于题目要求每个数组元素只能访问一次,不用辅助存储空间,可以从原理上入手,采用数学求和法,因为只有一个数字重复一次,而数又是连续的,根据累加和原理,对数组的所有项求和,然后减去 1 至 N - 1 的和,即为所求原创 2016-06-26 20:49:30 · 4961 阅读 · 0 评论 -
判断整数 x 能否表示成 n(n >= 2)个连续正整数的和
题目:如何判断一个整数 x 是否可以表示成 n(n >= 2)个连续正整数的和。 思路分析: (1)假设 x 可以表示成 n(n >= 2)个连续正整数的和,那么数学表达式如下:x = m + (m + 1) + (m + 2) + … + (m + n - 1),其中 m 为分解成的连续整数中最小的那一个(且 m 是大于等于 1 的正整数),可推出 x = (2m + n - 1)*n/2,变原创 2016-06-25 22:14:49 · 4756 阅读 · 1 评论 -
如何计算出序列的前n项数据
题目:正整数序列 Q 中的每个元素都至少能被正整数 a 和 b 中的一个整除,现给定 a 和 b,如何计算出 Q 中的前几项?例如,当 a=3,b=5,N=6时,序列为3,5,6,9,10,12。思路分析:可以和归并排序联系起来,给定两个数组 A、B,数组 A 存放:3 x 1,3 x 2,3 x 3,… 数组 B 存放 5 x 1,5 x 2,5 x 3,… 有两个指针 i、j,分别指向 A、B原创 2016-06-25 20:06:06 · 1622 阅读 · 0 评论 -
找出数组中第二大的数
题目:如何找出一个数组中第二大的数。 分析:如果仅仅只考虑实现,而不考虑时间效率,可以首先通过排序算法,将数组进行排序,然后根据数据下标来访问数组中第二大的数。最快的排序算法一般为快速排序算法,但是其时间复杂度仍然为O(nlogn),根据下标访问需要遍历一遍数组,时间复杂度为O(n),所以总的时间复杂度为O(nlogn)。如何只通过一遍扫描数组即可找出数组中第二大的数? 方法:通过设置两个变量来原创 2016-06-25 19:13:49 · 13086 阅读 · 3 评论 -
重排数组使得数组左边为奇数,右边为偶数
题目:给定一个存放整数的数组,如何重新排列数组使得数组左边为奇数,右边为偶数?要求:空间复杂度为O(1),时间复杂度为O(n)。 分析:采用类似快速排序的处理。可以用两个指针分别指向数组的头和尾,头指针正向遍历数组,找到第一个偶数,尾指针逆序遍历数组,找到第一个奇数,交换两个指针指向的数字,然后两指针沿着相应的方向继续向前移动,重复上述步骤,直到头指针大于等于尾指针为止。具体实现如下:#inclu原创 2016-06-25 16:57:52 · 4574 阅读 · 1 评论 -
找出数组中符合条件的数对的个数
题目:一个整型数组,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。 方法一:排序+二分查找。先对数组进行排序,然后遍历该有序数组,同时使用二分查找方法,查找对应的值是否存在(例如,有序数组中某元素值为a,那么在该有序数组中,使用二分查找方法,来查找(N+1- a)是否存在)。方法二:排序原创 2016-06-25 16:00:07 · 5960 阅读 · 0 评论 -
找出数组中出现奇数次的元素
题目:给定一个含有n个元素的整型数组array,其中只有一个元素出现奇数次,找出这个元素。 分析:因为对于任意一个数 k,k^k = 0,k^0 = k,所以将array中所有元素进行异或,那么个数为偶数的元素异或后都变成了0,只留下了个数为奇数的那个元素。#include <iostream>int FindData(int arr[], int len){ int num = arr原创 2016-06-24 22:07:30 · 8480 阅读 · 0 评论