1 算法思想
2 数组系列
类别-编号 |
题目 |
来源 |
1 |
二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否有该整数
输入: 4 4 5 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 4 4 7 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 输出: NO YES |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39092133 关键: 1 应该从右上角开始计算,若矩阵值比搜索值大,则排除这一列 小,则排除这一行 因为每次的都是当前的最右上角
代码: const int MAXSIZE = 1001; int iArr[MAXSIZE][MAXSIZE];
void searchArr(int n,int m,int iVal)//回去研究一下,二维数组如何传参数的形式 { if(iArr == NULL || n <= 0 || m<= 0)//鲁棒性 { return; } int row = 0; int column = m - 1; bool isFound = false; while(row < n && column >= 0) { if(iArr[row][column] > iVal) { column--; } else if(iArr[row][column] < iVal) { row++; } else { isFound = true; break; } } if(isFound) { printf("Yes\n"); } else { printf("No\n"); } } |
2 |
旋转数组的最小数字 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转, 输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
输入: 5 3 4 5 1 2 5 1 2 3 4 5 5 1 0 1 1 1 1 1 1 0 1 输出: 1 1 0 0 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39092329 关键: 1 中间元素与最左边比,若>=最左边元素,则使low = mid,注意不是low = mid -1,因为要始终确保第一个指针 指向的是左边递增序列的元素,第二个指针指向的是右边递增序列的元素 2 中间元素与最右边比,若<=最右边元素,则使high = mid, 3 循环终止条件是:high = low + 1,此时第二个指针指向的就是最小的元素 4 未考虑该排序数组没有旋转,此时直接返回第一个数字 if(iArr[low] < iArr[high])//检测数组是否已经排好序,直接看第一个数与最后一个数,若第一个数小于第二个数,就直接返回第一个数 5 未考虑左边,中间,右边数字相同时的情况。 if(iArr[mid] == iArr[low] && iArr[low] == iArr[high])//这里要追加,如果左边,中间,右边三者相同时,只能采用顺序查找 6未考虑鲁棒性 if(iArr == NULL || low < 0 || high < 0)//鲁棒性 { throw new exception("无效的参数"); }
代码: const int MAXSIZE = 1000001; int iArr[MAXSIZE];
using namespace std;
int orderSearch(int low,int high) { if(iArr == NULL || low < 0 || high < 0) { throw new exception("无效的参数"); } int iMin = iArr[low]; for(int i = low + 1; i <= high; i++) { if(iArr[i] < iMin) { iMin = iArr[i]; } } return iMin; }
int binarySearch(int low,int high) { if(iArr == NULL || low < 0 || high < 0)//鲁棒性 { throw new exception("无效的参数"); } if(iArr[low] < iArr[high])//检测数组是否已经排好序,直接看第一个数与最后一个数,若第一个数小于第二个数,就直接返回第一个数 { return iArr[low]; } int mid; while(low + 1 < high)//一旦low + 1 = high就循环结束 { mid = low + (high - low)/2; if(iArr[mid] == iArr[low] && iArr[low] == iArr[high])//这里要追加,如果左边,中间,右边三者相同时,只能采用顺序查找 { return orderSearch(low,high); } if(iArr[mid] >= iArr[low]) { low = mid; } else if(iArr[mid] <= iArr[high]) { high = mid; } } return iArr[high]; } |
3 |
调整数组顺序使奇数(odd)位于偶数(even)前面: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分
输入: 每个输入文件包含一组测试案例。 对于每个测试案例,第一行输入一个n,代表该数组中数字的个数。 接下来的一行输入n个整数。代表数组中的n个数。 输出: 对应每个测试案例, 输入一行n个数字,代表调整后的数组。注意,数字和数字之间用一个空格隔开,最后一个数字后面没有空格。 样例输入: 5 1 2 3 4 5 样例输出: 1 3 5 2 4 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39138129 关键 1 可扩展性版本: void reorder(int* pArr,int iLen,bool (*pFun)(int n))//针对可扩展性的版本,注意:函数指针格式:返回值(*指针名)(形参列表) bool isEven(int n)//判断是否是偶数 { return (n & 0x1) == 0; } 2 if(pFront < pBack)//注意,这里一定要加这个判断 { int iTemp = *pFront; *pFront = *pBack; *pBack = iTemp; } 3 if(!pFun(pArr[i]) && pFun(pArr[i-1]))//如果当前数是奇数,并且其前面的数是偶数 { int iTemp = pArr[i]; for(int k = i - 1 ; k >= i - iEvenNum; k--)//易错,将恰面的n个偶数向后挪动,应该从后向前 { pArr[k+1] = pArr[k]; }
代码 /应该先从前向后,在确保当前数是奇数,且前面N个数是偶数的情况下,把前面n个偶数依次后移,然后将最后的奇数调至第一个偶数处 //1 3 2 4 5 void reorder_keepSeq(int* pArr,int iLen,bool (*pFun)(int n))//保持奇数与奇数,偶数与偶数之间的相对顺序不变,只能采用碰到一个 { int iEvenNum = 0; for(int i = 0 ; i < iLen ; i++) { if(pFun(pArr[i]))//统计偶数的个数 { iEvenNum++; } if(i)//如果i不为0,开始统计 { if(!pFun(pArr[i]) && pFun(pArr[i-1]))//如果当前数是奇数,并且其前面的数是偶数 { int iTemp = pArr[i]; for(int k = i - 1 ; k >= i - iEvenNum; k--)//易错,将前面的n个偶数向后挪动,应该从后向前 { pArr[k+1] = pArr[k]; } pArr[i-iEvenNum] = iTemp;//将奇数调整到前面 } } } } |
4 |
顺时针打印矩阵
输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行包括两个整数m和n(1<=m,n<=1000):表示矩阵的维数为m行n列。 接下来的m行,每行包括n个整数,表示矩阵的元素,其中每个元素a的取值范围为(1<=a<=10000)。 输出: 对应每个测试案例,输出一行, 按照从外向里以顺时针的顺序依次打印出每一个数字,每个数字后面都有一个空格。 样例输入: 4 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 样例输出: 1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39138239 关键: 1 int iCnt = 1;//这边计数器必须从1开始,否则陷入无限循环。到m*n跳出,共有m*n-1+1=m*n个元素 2 //采用试探法从左向右,防止y越界。这里最牛逼的方法就是:通过对横纵坐标的累加或累减以剪枝判定下一次蛇形的上下界 while(iy + 1 < n && !bMark[ix][iy+1]) { printf("%d ",iMatrix[ix][++iy]); bMark[ix][iy] = true; ++iCnt; } //从上向下,防止x越界 while(ix + 1 < m && !bMark[ix+1][iy]) 3注意,这里采用了对4个方向的模拟操作
const int MAXSIZE = 1001; int iMatrix[MAXSIZE][MAXSIZE]; bool bMark[MAXSIZE][MAXSIZE];
void snakeNum(int m,int n) { int ix = 0,iy = 0; int iCnt = 1;//这边计数器必须从1开始,否则陷入无限循环。到m*n跳出,共有m*n-1+1=m*n个元素 printf("%d ",iMatrix[ix][iy]); bMark[ix][iy] = true; while(iCnt < m*n) { //采用试探法从左向右,防止y越界。这里最牛逼的方法就是:通过对横纵坐标的累加或累减以剪枝判定下一次蛇形的上下界 while(iy + 1 < n && !bMark[ix][iy+1]) { printf("%d ",iMatrix[ix][++iy]); bMark[ix][iy] = true; ++iCnt; } //从上向下,防止x越界 while(ix + 1 < m && !bMark[ix+1][iy]) { printf("%d ",iMatrix[++ix][iy]); bMark[ix][iy] = true; ++iCnt; } //从右向左,防止y越界 while(iy - 1 >= 0 && !bMark[ix][iy-1]) { printf("%d ",iMatrix[ix][--iy]); bMark[ix][iy] = true; ++iCnt; } //从下向上,防止x越界, while(ix - 1 >= 0 && !bMark[ix-1][iy]) { printf("%d ",iMatrix[--ix][iy]); bMark[ix][iy] = true; ++iCnt; } } printf("\n"); } |
5 |
数组中出现次数超过一半的数字: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
输入: 每个测试案例包括2行: 第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。 第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。 输出: 对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。 样例输入: 9 1 2 3 2 2 2 5 4 2 8 1 2 3 2 2 5 4 2 样例输出: 2 -1 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39138401 关键: 1 基于Partition函数的O(n)解法: 如果将数组排序,那么数组中间的数字时出现次数超过数组长度一半的数字。 用随机选择快速排序算法,在数组中随机选择一个数字,如果选中的数字的下标刚好是n/2,这个数字就是中位数。 如果选中的下标大于n/2,那么中位数在它的左边。 2 swap(&iArr[low],&iArr[iIndex]);//注意:快速排序之随机枢轴版中,注意要将随机枢轴与iArr[low]进行交换 3 int iIndex = partition(low,high); while(iIndex != iMid) { if(iIndex > iMid)//如果下标大于中间,应该向左缩小范围 { high = iIndex - 1; } 4 for(int i = 0 ; i < iLen ; i++)//注意,需要检查是否真正出现的次数超过了一半 { if(iRes == iArr[i]) { iCnt++; } } if(iCnt*2 <= iLen) 5 根据数组特点找出O(n)的算法: 数组中有一个数字出现的次数超过数组长度的一半 = 出现次数>其他所有数字出现次数和 要找的数字出现的次数比其他所有数字出现的次数之和都要多,因此要找的数字肯定是最后一次把次数 设为1时对应的数字。?为什么是最后一次设为1。因为只有最后一次设为1说明相同的数字个数>不同的数字个数 6 if(iTimes == 0)//如果次数减为0,就令结果为当前数,并使次数为1 { iRes = iArr[i]; iTimes = 1; } else if(iRes == iArr[i])//如果当前数与之前保存的数相同,就累加 { iTimes++; } else//如果当前数与之前保存的数不同,就累减
代码 int moreThanHalfNum2(int iLen) { int iRes = iArr[0]; int iTimes = 1; for(int i = 1 ; i < iLen ;i++) { if(iTimes == 0)//如果次数减为0,就令结果为当前数,并使次数为1 { iRes = iArr[i]; iTimes = 1; } else if(iRes == iArr[i])//如果当前数与之前保存的数相同,就累加 { iTimes++; } else//如果当前数与之前保存的数不同,就累减 { iTimes--; } } int iCnt = 0; for(int i = 0 ; i < iLen ; i++) { if(iRes == iArr[i]) { iCnt++; } } if(iCnt*2 <= iLen) { return -1; } else { return iRes; } } |
6 |
把数组排成最小的数: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接处的所有数字中的最小的一个。例如 输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323
输入: 输入可能包含多个测试样例。 对于每个测试案例,输入的第一行为一个整数m (1<=m <=100)代表输入的正整数的个数。 输入的第二行包括m个正整数,其中每个正整数不超过10000000。 输出: 对应每个测试案例, 输出m个数字能排成的最小数字。 样例输入: 3 23 13 6 2 23456 56 样例输出: 13236 2345656 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39187735 关键: 1 我们应该对于给出的两个数字m和n,需要确定规则m和n哪个应该排序在前面,而不是比谁大谁小。 m和n能拼成mn或者nm,当mn 由于m和n都在int中,而拼接之后可能溢出,因此用字符串法来处理大数问题。 由于mn和nm位数相同,所以比较大小只需按照字符串大小比较即可。 2 char** strNumbers = (char**)(new int[iLen]);//经典,这里定义二级指针,strNumbers是指向字符指针的指针,而字符指针又指向每个字符串 3 for(int i = 0 ; i < iLen ; i++)//对每个字符指针new一下,然后写入整数 { strNumbers[i] = new char[MAXLEN + 1]; sprintf(strNumbers[i],"%d",pArr[i]);//用字符串解决大数问题 4 qsort(strNumbers,iLen,sizeof(char*),compare); //void qsort(void* buf,size_t num,size_t size,int(*compare)(const void*,const void*)),qsort一半适用于二级字符指针的字符数组时间比较,sort不行 5 for(int k = 0 ; k < iLen ; k++)//注意先删除一级指针,再删除二级指针 { delete[] strNumbers[k]; } delete[] strNumbers; 6 int compare(const void* str1,const void* str2)//qsort比较函数所用形参必须是const void* 7 strcpy(strNum1,*(const char**)str1);//注意,如果改成strcpy(strNum1,(const char*)str1),是不能实现排序的,不知道为什么 ? strcat(strNum1,*(const char**)str2); 代码: const int MAXSIZE = 101; const int MAXLEN = 10; //int compare(const char* str1,const char* str2) int compare(const void* str1,const void* str2)//qsort比较函数所用形参必须是const void* { char strNum1[2*MAXLEN + 1]; char strNum2[2*MAXLEN + 1]; strcpy(strNum1,*(const char**)str1);//注意,如果改成strcpy(strNum1,(const char*)str1),是不能实现排序的,不知道为什么 ? strcat(strNum1,*(const char**)str2); strcpy(strNum2,*(const char**)str2); strcat(strNum2,*(const char**)str1); return strcmp(strNum1,strNum2); } void printMinNum(int* pArr,int iLen) { if(!pArr || iLen < 1 || iLen > 100) { return; } char** strNumbers = (char**)(new int[iLen]);//经典,这里定义二级指针,strNumbers是指向字符指针的指针,而字符指针又指向每个字符串 for(int i = 0 ; i < iLen ; i++)//对每个字符指针new一下,然后写入整数 { strNumbers[i] = new char[MAXLEN + 1]; sprintf(strNumbers[i],"%d",pArr[i]);//用字符串解决大数问题 } //sort(strNumbers,strNumbers + iLen,compare);//采用我们自定义的比较函数进行比较 qsort(strNumbers,iLen,sizeof(char*),compare); //void qsort(void* buf,size_t num,size_t size,int(*compare)(const void*,const void*)),qsort一半适用于二级字符指针的字符数组时间比较,sort不行 for(int j = 0 ; j < iLen ; j++) { printf("%s",strNumbers[j]); } printf("\n"); for(int k = 0 ; k < iLen ; k++)//注意先删除一级指针,再删除二级指针 { delete[] strNumbers[k]; } delete[] strNumbers; } |
7 |
丑数 我们把只包含因子2、3和5的数称为丑数,求按照从小到大的顺序的第1500个丑数。例如6,8都是丑数,但14不是丑数,因为它包含因此7.习惯上我们把1当做第一个丑数
输入: 输入包括一个整数N(1<=N<=1500)。 输出: 可能有多组测试数据,对于每组数据, 输出第N个丑数。 样例输入: 3 样例输出: 3 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39187761 关键: 1 对于乘以2而言,存在丑数T2,排在它之前的每个丑数乘以2得到的结果<已有最大丑数,在它之后的每个丑数*2 会太大。我们只需记录这个丑数的位置,同时每次生成新的丑数是,更新T2,对乘3和乘5而言,同样存在T3和T5。 2 pMul2 = pMul3 = pMul5 = iUglyNumArr;//初始设定丑数数组中乘以2或3或5后,大于丑数数组中最大值的丑数指针为起始值 3 int iMin = min(*pMul2*2,*pMul3*3,*pMul5*5);//选定丑数 iUglyNumArr[iNextIndex] = iMin;//设定下一个丑数 while(*pMul2*2 <= iMin)//更新丑数数组*(2或3或5)大于当前丑数数组中最大值的丑数的位置 { pMul2++; }
代码
int getUglyNum(int n) { if(n < 0 || n > 1500) { return -1; } int iUglyNumArr[MAXSIZE]; iUglyNumArr[0] = 1; int iNextIndex = 1; int* pMul2,*pMul3,*pMul5; pMul2 = pMul3 = pMul5 = iUglyNumArr;//初始设定丑数数组中乘以2或3或5后,大于丑数数组中最大值的丑数指针为起始值 while(iNextIndex < n) { int iMin = min(*pMul2*2,*pMul3*3,*pMul5*5);//选定丑数 iUglyNumArr[iNextIndex] = iMin;//设定下一个丑数 while(*pMul2*2 <= iMin)//更新丑数数组*(2或3或5)大于当前丑数数组中最大值的丑数的位置 { pMul2++; } while(*pMul3*3 <= iMin) { pMul3++; } while(*pMul5*5 <= iMin) { pMul5++; } iNextIndex++; } return iUglyNumArr[n -1]; } |
8 |
数字在排序数组中出现的次数 统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组 中出现了4次,因此输出4
输入: 每个测试案例包括两行: 第一行有1个整数n,表示数组的大小。1<=n <= 10^6。 第二行有n个整数,表示数组元素,每个元素均为int。 第三行有1个整数m,表示接下来有m次查询。1<=m<=10^3。 下面有m行,每行有一个整数k,表示要查询的数。 输出: 对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数。 样例输入: 8 1 2 3 3 3 3 4 5 1 3 8 0 2 3 3 3 3 4 5 2 1 6 样例输出: 0 0 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39187921 本质上是lowerBound和upperBound问题的翻版 lowerBound: upperBound: 1 2 3 3 3 3 4 5 lowerBound:本质是在二分查找的基础上寻求当前值v第一次出现的位置,或者是在当前位置插入v之后仍然有序的 位置, 当iArr[mid] > val时,这时候范围只可能是[low,mid] 当iArr[mid] = val时,范围是[low,mid],mid可能取到 当iArr[mid] < val时,mid不可能,范围是[mid+1,high] upperBound:主要实在寻求当前值v最后一次出现的位置(的后面的位置,易错),或者当前位置插入v之后仍然有序的位置 当v存在时返回它出现的最后一个位置的后面的一个位置。如果不存在,返回这样一个下标i:在此处插入v(原来的元素A[i],A[i+1],..全部 往后移动一个位置)后序列仍然有序。 当iArr[mid] > val时,中间大于被搜索,缩小范围high = mid,mid是有可能的 iArr[mid] = val时,mid是有不可能的low = mid+1,因为必须返回当前元素最后出现的位置后面的一个位置 iArr[mid] < val时,mid不可能low = mid + 1
关键: 1 else//注意在upperBound中,当_iDataArr[mid] = iSeaVal,由于我们寻找的是被查找元素后面的一个位置,因此low = mid + 1,而不是low = mid { low = mid + 1;
代码
int _iDataArr[MAXSIZE]; int _iSearchArr[MAXSIZE];
int lowerBound(int low,int high,int iSeaVal) { int mid; while(low < high) { mid = low + (high - low)/2; if(_iDataArr[mid] < iSeaVal)//中间值小于搜索值,那么说明中间偏小,此时应使low更新 { low = mid + 1; } else { high = mid; } } return low; }
int upperBound(int low,int high,int iSeaVal) { int mid; while(low < high) { mid = low + (high - low)/2; if(_iDataArr[mid] > iSeaVal) { high = mid; } else//注意在upperBound中,当_iDataArr[mid] = iSeaVal,由于我们寻找的是被查找元素后面的一个位置,因此low = mid + 1,而不是low = mid { low = mid + 1; } } return low; } |
9 |
数组中只出现一次的数字: 一个整型数组里除了两个数字之外,其他的数字都出现了两个,请写程序找出这两个只出现一次的数字。要求时间 复杂度是O(n),空间复杂度是O(1)
输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组大小。2<=n <= 10^6。 第二行包含n个整数,表示数组元素,元素均为int。 输出: 对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。 样例输入: 8 2 4 3 6 3 2 5 5 样例输出: 4 6 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39187969 关键: 1 我们从头到尾异或,结果是两个只出现一次的数字的异或结果。异或的结果部位0,至少二进制表示中有一位为1, 在结果数字中找到第一个为1的位置,记为第n位。以第n位是不是1为标准把原数组中的数字分成两个子数组 a^a = 0,任何一个数字异或自己为0 2 while( ((num & 1) == 0) && (iIndex < 8*sizeof(int)) )//某数与1相与为0表明该数最低位为0,注意不能超过int的总位数,防止是负数陷入死循环 { num = num >> 1;//向右表示除以2
代码 const int MAXSIZE = 1e6 + 1; int _iArr[MAXSIZE];
int first1Bit(int num)//寻找一个数从低位到高位第一次出现1的位置 { int iIndex = 0; while( ((num & 1) == 0) && (iIndex < 8*sizeof(int)) )//某数与1相与为0表明该数最低位为0,注意不能超过int的总位数,防止是负数陷入死循环 { num = num >> 1;//向右表示除以2 iIndex++; } return iIndex; }
bool isValid(int num,int iIndex)//判断一个数的二进制位第n位是不是1,例如:2,0010,第1位是1,右移1位得001,若与0相与为1,即是 { for(int i = 1 ; i <= iIndex ; i++)//右移iIndex位 { num = num >> 1; } if((num & 1) != 0) { return true; } else { return false; } }
void appear1Times(int n) { int iOr = 0;//设定异或初始值为0,O^a = a,0^a^a = 0 for(int i = 0 ; i < n; i++)//刚开始,把整个数组先异或一遍 { iOr = iOr ^ _iArr[i]; } int iIndex = first1Bit(iOr); //接下来用最右边的二进制1来将数组划分为:两个数组,每个数组中只包含一个出现1次的数字,其余出现的次数为两次 int iOr_1 = 0,iOr_0 = 0; for(int j = 0 ; j < n; j++) { if(isValid(_iArr[j],iIndex)) { iOr_1 = iOr_1 ^ _iArr[j]; } else { iOr_0 = iOr_0 ^ _iArr[j]; } } if(iOr_1 < iOr_0) { printf("%d %d\n",iOr_1,iOr_0); } else { printf("%d %d\n",iOr_0,iOr_1); } } |
11 |
和为s的两个数字 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得他们的和正好是s。如果有多对数字的和等于s, 输出任意一对即可。 例如输入数组{1、2、4、7、11、15}和数字15.由于4+11=15,因此输出4和11。
输入: 每个测试案例包括两行: 第一行包含一个整数n和k,n表示数组中的元素个数,k表示两数之和。其中1 <= n <= 10^6,k为int 第二行包含n个整数,每个数组均为int类型。 输出: 对应每个测试案例,输出两个数,小的先输出。如果找不到,则输出“-1 -1” 样例输入: 6 15 1 2 4 7 11 15 6 14 1 2 4 7 11 15 样例输出: 4 11 -1 -1 |
剑指offer https://blog.csdn.net/qingyuanluofeng/article/details/39188001 关键: 1 定义两个指针,一个从前开始指向,一个从后开始指向。向中间靠拢。 一定要注意限制条件是已经排好序的数组 2 if(*pFront + *pBack < iSum)//如果小于sum,那么把较小的指针向后移动 { pFront++; }
代码 const int MAXSIZE = 1e6 + 1; int _iArr[MAXSIZE];
using namespace std;
pair { int* pBack = &_iArr[n-1],*pFront = &_iArr[0]; while((pFront < pBack) && (*pFront + *pBack != iSum)) { if(*pFront + *pBack < iSum)//如果小于sum,那么把较小的指针向后移动 { pFront++; } else { pBack--; } } if(pFront != pBack)//如果两者不等,说明肯定找到了 { return make_pair } else { return make_pair } } |
12 |
斜数组之找规律 找出如下图的规律
输入: 4 5 输出: 1 5 2 8 6 3 10 9 7 4 1 6 2 10 7 3 13 11 8 4 15 14 12 9 5 |
算法设计与分析 https://blog.csdn.net/qingyuanluofeng/article/details/47189165 关键: 1 找规律的题目,分析原始行列下标与现有下标之间的关系 第一行 第二行 第三行 第四行 斜行 原始 斜行 原始 斜行 原始 斜行 原始 [1,1]-[1,1] [2,1]-[2,1] [3,1]-[3,1] [4,1]-[4,1] [1,2]-[2,2] [2,2]-[3,2] [3,2]-[4,2] [1,3]-[3,3] [2,3]-[4,3] [1,4]-[4,4] 找规律 斜行 原始 [i,j]-[i-1+j,j] 斜行i取值(1~n) 列j取值(1~n+1-i) 因为斜行最大值为:n = i - 1 + j,j = n - i + 1,i又取值[1~n] 2 找规律 斜行 原始 [i,j]-[i-1+j,j] 斜行i取值(1~n) 列j取值(1~n+1-i) 因为斜行最大值为:n = i - 1 + j,j = n - i + 1,i又取值[1~n] 3 iArr[i - 1 + j][j] = iCnt++;//表示出斜行,即根据原始矩阵确定新的矩阵的存储位置
代码: const int MAXSIZE = 100;
void printGraph(int n) { int iCnt = 1; int iArr[MAXSIZE][MAXSIZE]; for(int i = 1 ; i <= n ; i++) { for(int j = 1 ; j <= n - i + 1 ; j++) { iArr[i - 1 + j][j] = iCnt++;//表示出斜行 } } for(int i = 1 ; i <= n ; i++) { for(int j = 1 ; j <= i ; j++) { printf("%d ",iArr[i][j]); } printf("\n"); } } |
13 |
寻找发帖水王 Tango是微软亚洲研究院的一个试验项目。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发贴,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗? |
编程之美 https://blog.csdn.net/qingyuanluofeng/article/details/47187115 参见题目5,与剑指offer题目相同 |
14 |
寻找发帖超过总帖1/4的水王 有3个发帖很多的ID,他们发帖数目都超过了帖子总数目N的1/4,你能从ID列表中找出它们的ID吗?
输入:(针对2两个水王) 9 1 2 3 2 3 2 3 2 3 输出: 2 3 输入:(针对3个水王) 16 1 2 3 4 2 3 4 2 3 4 2 3 4 2 3 4 输出: 2 3 4 |
编程之美 https://blog.csdn.net/qingyuanluofeng/article/details/47187061 关键: 1 if(iRet1 == pArr[i])//如果当前是水王,则次数累加;如果次数为0,重新赋值次数,如果不是,全部次数减1 { iTimes1++; } 2 else if(iTimes1 == 0)//如果次数为0,重新赋值次数 { iTimes1 = 1; iRet1 = pArr[i]; 3 else { iTimes1--; iTimes2--; iTimes3--;
代码: const int MAXSIZE = 10000; const int INF = 1000000000;
void thirdTimesNum(int* pArr,int iLen) { int iRet1 = INF,iRet2 = INF; int iTimes1 = 0,iTimes2 = 0; for(int i = 0 ; i < iLen ; i++) { if(iTimes1 == 0) { if(iRet2 == pArr[i])//这个绝对有问题 { iTimes2++; } else { iRet1 = pArr[i]; iTimes1++; } } else if(iTimes2 == 0) { if(iRet1 == pArr[i]) { iTimes1++; } else { iRet2 = pArr[i]; iTimes2++; } } else { if(iRet1 == pArr[i]) { iTimes1++; } else if(iRet2 == pArr[i]) { iTimes2++; } else { iTimes1--; iTimes2--; } } } printf("%d %d\n",iRet1,iRet2); }
void forthTimesNum(int* pArr,int iLen) { int iRet1 = INF,iRet2 = INF,iRet3 = INF; int iTimes1,iTimes2,iTimes3; iTimes1 = iTimes2 = iTimes3 = 0; for(int i = 0 ; i < iLen ; i++) { if(iRet1 == pArr[i])//如果当前是水王,则次数累加;如果次数为0,重新赋值次数,如果不是,全部次数减1 { iTimes1++; } else if(iRet2 == pArr[i]) { iTimes2++; } else if(iRet3 == pArr[i]) { iTimes3++; } else if(iTimes1 == 0)//如果次数为0,重新赋值次数 { iTimes1 = 1; iRet1 = pArr[i]; } else if(iTimes2 == 0) { iTimes2 = 1; iRet2 = pArr[i]; } else if(iTimes3 == 0) { iTimes3 = 1; iRet3 = pArr[i]; } else { iTimes1--; iTimes2--; iTimes3--; } } printf("%d %d %d\n",iRet1,iRet2,iRet3); } |
15 |
子数组的最大乘积 给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合中乘积最大的一组,并写出算法的时间复杂度
输入: 5 5 3 8 6 7 输出: 1680 |
编程之美 https://blog.csdn.net/qingyuanluofeng/article/details/47187309
关键: 1 p[i] = s[i-1] * t[i];//s[i]表示数组前i个元素的乘积,s[0]表示数组前0个元素乘积设为1,s[1] = pArr[0],t[i]表示数组最后(n-i)个元素的成绩, //t[n] 表示数组最后0个元素的乘积,设为1,t[n-1] = pArr[n-1],p[i]表示缺掉了第i个元素,其中这第i个元素实际上下标为i-1 2 计算N-1个数的组合乘积,假设第i个(0<=i<=N-1)元素 被排除在乘积之外 设array[]为初始数组,s[i]表示数组前i个元素的乘积,s[i] = 从1到i对array[i-1]累乘,s[0] = 1(边界条件),那么s[i] = s[i-1]*array[i-1] 设t[i]表示数组后(N-i)个元素的成绩,t[i] = 从i到n对array[i]累乘,t[N+1] = 1,呢么t[i] = t[i+1]*array[i] 设p[i]为数组除第i个元素外,其他N-1个元素的乘积,即有: p[i] = s[i-1]*t[i+1]
代码: const int MAXSIZE = 10000;
long long maxProduct(int* pArr,int iLen) { long long s[MAXSIZE]; s[0] = 1; long long t[MAXSIZE]; t[iLen] = 1; for(int i = 1 ; i <= iLen ; i++)//从前向后遍历数组 { s[i] = s[i-1] * pArr[i-1]; } for(int j = iLen - 1; j >= 0 ; j--)//从后向前遍历数组 { t[j] = t[j+1] * pArr[j];//t[n] } long long p[MAXSIZE]; for(int i = 1 ; i <= iLen ; i++) { p[i] = s[i-1] * t[i];//s[i]表示数组前i个元素的乘积,s[0]表示数组前0个元素乘积设为1,s[1] = pArr[0],t[i]表示数组最后(n-i)个元素的成绩, //t[n] 表示数组最后0个元素的乘积,设为1,t[n-1] = pArr[n-1],p[i]表示缺掉了第i个元素,起始这第i个元素实际上下标为i-1 } long long lMax = p[1]; for(int i = 2 ; i <= iLen ; i++) { if(p[i] > lMax) { lMax = p[i]; } } return lMax; } |
16 |
数组循环移位 设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量。
输入: 6 10 5 6 1 2 3 4 输出: 1 2 3 4 5 6 |
编程之美 https://blog.csdn.net/qingyuanluofeng/article/details/47187399
关键: 1 k %= iLen;//防止k大于n,简化循环右移的处理 设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量。 此题已经做过,但本题的收获是注意循环移位,即,当K大于N时,注意到移N位后与没移位是一样的效果。因此 k %= n; 2 rightShift(pArr,0,iLen - k -1);//应该先移动n - k - 1个元素而不是k -1
代码:
void rightShift(int* pArr,int low,int high) { int iTemp; for(; low < high ; low++,high--) { iTemp = pArr[low]; pArr[low] = pArr[high]; pArr[high] = iTemp; } }
void reverse(int* pArr,int iLen,int k) { if(!pArr || iLen <= 0) { return; } k %= iLen;//防止k大于n,简化循环右移的处理 rightShift(pArr,0,iLen - k -1);//应该先移动n - k - 1个元素而不是k -1 rightShift(pArr,iLen - k,iLen-1); rightShift(pArr,0,iLen-1); } |
17 |
将图像旋转90度 给定一副由N*N矩阵表示的图像,其中每个像素的大小为4字节,编写一个方法,将图像旋转90度。不占用额外空间能否做到?
输入: 3(N) 0 1 2 3 4 5 6 7 8 输出: 6 3 0 7 4 1 8 5 2 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/53763546 分析:4字节,这里就是int。关键应该是找到旋转公式。 0 1 2 3 4 5 6 7 8 顺时针旋转后变成 6 3 0 7 4 1 8 5 2 问题转化为如何求N*N矩阵旋转90度的公式,这个忘记了 书上解法: 将矩阵旋转90度(顺时针),一层一层旋转,每一层执行环状旋转,将上边移到右边,右边移到下边, 下边移到左边,左边移到上边 注意规律是: 规律1: 上边横坐标=左边纵坐标 左边横坐标=下边纵坐标 所以: 旋转后的方向[横坐标,] = [,横坐标] 规律2: 旋转后的方向[,纵坐标] = [n-1-纵坐标,] 距离: 当n=4,有4行时 m[0,0] = m[3,0] m[0,1] = m[2,0] 综上规律为: 旋转后的方向[x,y] = 原方向[n-1-y,x]
关键: 1 旋转后方向[x,y] = 原方向[n-1-y,x] 2 需要确定大的每一层旋转的次数,layer为0~n/2-1 对于每一层上旋转的元素为: i从layer到n-1-layer, 同时得到对于每一个元素的偏移量为i-first //令上边等于左边旋转,这里的first为行数 matrix[first][i] = matrix[last - offset][first]; 3 //确定总共旋转的层数为0~n/2 for(int layer = 0 ; layer < n/2 ; layer++) { int first = layer; int last = n - 1 - layer; //开始依次遍历需要循环的 0~ n-1个元素(第n-1个元素取不到) for(int i = first ; i < last ; i++) { //设置偏移量,该偏移量作用于旋转后方向的纵坐标 int offset = i - first; int top = matrix[first][i]; //令上边等于左边旋转,这里的first为行数 matrix[first][i] = matrix[last - offset][first];
代码: void matrixRotate(int n) { //确定总共旋转的层数为0~n/2 for(int layer = 0 ; layer < n/2 ; layer++) { int first = layer; int last = n - 1 - layer; //开始依次遍历需要循环的 0~ n-1个元素(第n-1个元素取不到) for(int i = first ; i < last ; i++) { //设置偏移量,该偏移量作用于旋转后方向的纵坐标 int offset = i - first; int top = matrix[first][i];
//令上边等于左边旋转,这里的first为行数 matrix[first][i] = matrix[last - offset][first];
//令左边等于下边旋转 matrix[last-offset][first] = matrix[last][last - offset];
//令下边等于右边旋转 matrix[last][last - offset] = matrix[i][last];
//令右边等于上边 matrix[i][last] = top; } } }
int main(int argc, char* argv[]) { int n; while(cin >> n) { memset(matrix , 0 , sizeof(matrix)); for(int i = 0 ; i < n ; i++) { for(int j = 0 ; j < n ; j++) { cin >> matrix[i][j]; } } matrixRotate(n); printMatrix(n); } system("pause"); return 0; } |
18 |
若M*N矩阵中某个元素为0,则将其所在行与列清零 编写一个算法,若M*N矩阵中某个元素为0,则将其所在的行与列清零。
输入: 3(行) 4(列) 1 1 0 1 0 1 1 0 1 1 1 1 输出: 0 0 0 0 0 0 0 0 0 1 0 0 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/53764833 关键: 1 因为如果直接找到后就清零会导致后续所有矩阵元素变为0,因此真正的做法 是设置删除标记,记录当前零元素对应的行和列为真,然后遍历矩阵时,遍历元素 的行或列只要为真就置为0,时间复杂度为O(N^2) 2 //根据行列清零标记进行清零 for(int i = 0 ; i < row ; i++) { for(int j = 0 ; j < column ; j++) { if( rowArr[i] || columnArr[j]) { matrix[i][j] = 0;
代码:
const int MAXSIZE = 100; int matrix[MAXSIZE][MAXSIZE];
void clearZero(int row , int column , int matrix[][MAXSIZE]) { int* rowArr = new int[row]; int* columnArr = new int[column]; memset(rowArr, 0 , sizeof(int) * row); memset(columnArr, 0 , sizeof(int) * column); //初始化清零的行和列标记 for(int i = 0 ; i < row ; i++) { for(int j = 0 ; j < column ; j++) { if( matrix[i][j] == 0) { rowArr[i] = 1; columnArr[j] = 1; } } }
//根据行列清零标记进行清零 for(int i = 0 ; i < row ; i++) { for(int j = 0 ; j < column ; j++) { if( rowArr[i] || columnArr[j]) { matrix[i][j] = 0; } } } delete[] rowArr; delete[] columnArr; }
int main(int argc,char* argv[]) { int row , column; while(cin >> row >> column) { for(int i = 0 ; i < row ; i++) { for(int j = 0 ; j < column ; j++) { cin >> matrix[i][j]; } } clearZero(row , column , matrix); printMatrix(row , column , matrix); } system("pause"); return 0; } |
19 |
有些数的素因子只有3,5,7,请设计一个算法,找出其中第k个数 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/54124669 与丑数是同一题,参考:题目7 丑数 |
20 |
给定M*N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/54378901 与剑指offer中题目相同,参考:题目1二维数组的查找 |
21 |
用C++方法,打印输入文件的最后K行。
输入: 4(倒数第K行) 输出:(这个是在我输入文件共有6行,各行分别为:1,2,3,4,5,6的情况下) 3 4 5 6 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/54392457
分析:假设文件一共N行,最后K行,那就是从N-k+1~N。之前打印链表倒数第k个结点可以用两个指针,这里不能用了。 暴力破解:先读取整个文件确定N,下次每读一行就计数,从第N-k+1行开始存储结果直到第N行。 另外一种方法就是:采用回滚数组,节省空间,设一个字符串数组strings[k],长度为k,每次存储新读取的一行到该数组, 举例:设共有6行,读取最后4行,各行内容如下 1 2 3 4 5 6 那么读取第1行数组中为:[1, , ], 数组元素个数 2 [1,2,],直接存储该行 3 [1,2,3],直接存储 4 [1,2,3,4],直接存储 5 [5,2,3,4],元素个数=K,必须替换掉最先进来的1 6 [5,6,3,4],替换次最先进来的2 记录最后一行在数组下标index,则index+1~k-1下标对应的数组元素是前面部分(如上述3,4),再加上0~index下标对应元素是后面部分(如上述的5,6) 关键: 1 采用回滚数组,节省空间,设一个字符串数组strings[k],长度为k,每次存储新读取的一行到该数组,当长度>=k时,采用替换最先进入的行 记录最后一行在数组下标index,则index+1~k-1下标对应的数组元素是前面部分,再加上0~index下标对应元素是后面部分 2 文件操作:读取一行用字符数组infile.getline(line , 1024);,判断是否结束用while(!infile.eof()),判断文件是否打开成功用if(!infile) 代码: void printResult(vector { if(lines.empty()) { cout << "no result" << endl; return; } int size = lines.size(); int i; for(i = endIndex + 1 ; i < size; i++) { cout << lines.at(i) << endl; } for(i = 0 ; i <= endIndex ; i++) { cout << lines.at(i) << endl; } } void process() { int k; while(cin >> k) { string fileName("test.txt"); ifstream infile(fileName); if(!infile) { cout << "file open error" << endl; return; } char line[1024];//读取一行,不能用字符串 vector int replaceIndex = 0; while(!infile.eof()) { infile.getline(line , 1024); string content(line); if(lines.size() < k) { lines.push_back(content); } //此时需要将最先进入的那一行替换掉 else { if(replaceIndex >= k) { replaceIndex = 0; } lines.at(replaceIndex) = content; replaceIndex++; } } //关闭文件 infile.close(); printResult(lines , replaceIndex - 1); } } |
22 |
给定一个整数数组,编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n - m越小越好,也就是说,找出符合条件的最短序列。
输入: 9(数组元素个数,接下来一行是n个元素) 1 3 5 9 8 7 4 6 13 13 1 2 4 7 10 11 7 12 6 7 16 18 19 输出: 2(m) 7(n) 3 9 |
程序员面试金典 https://blog.csdn.net/qingyuanluofeng/article/details/54576492 分析:我们将数组分成3个部分,A[0... m-1],A[m ... n],A[n+1...A.length-1] 那么必定要符合如下条件:前面数组的最大值要<=中间数组的最小值,中间数组的最大值要<=后面数组的最小值 如果数组已经有序,那么m,n都设置为-1 如果数组无序,可以遍历m和n,需要不断从中间数组中取出最小值和最大值并比较,符合条件就可以 时间复杂度= 不断尝试m和n的时间O(n^2) + 从中间数组选择最小值和最大值的的时间O(n)【可以采用线性时间选择算法,具体的算法我记得好像是数组不断划分为5的等分来做】 而且需要前面数组和后面数组都要有序
书上解法: 1 从左到右遍历,如果当前元素比后面元素大,记录当前元素位置low【牛逼,确定了左边有序序列】 从右到左遍历,如果当前元素比其前面元素小,记录该元素位置high 中间数组在下标low+1~high-1 寻找中间数组中最小值min,最大值max, 从low位置向前遍历,如果有元素的值 < min,记录其位置pos,则m = pos + 1, 从high位置向后遍历,如果有元素的值 > max,记录位置pos,则n= pos - 1;表明该元素前面部分都是<=max的,这是不符合题目要求的,所以设定n=pos-1 【这个解法是错误的】 例如:1 3 5 9 8 7 4 6 13, 寻找中间数组得到:[1 3 5 9] [8 7] [4 6 13] 对中间数组,确定左边中小于中间数组最小值,确定右边大于中间数组最大值,得:[1 2 5] [9 8 7 4 6] [13] 发现尽管对中间排好序,但是 5 大于 4,仍然不是有序的 如果继续对数组: [1 2 5] [9 8 7 4 6] [13]重复上述处理,找到[9 8 7 4 6]中最小值为4,最大值为9, 发现修改左边下标为2,把5包含进来,得到最终 [1 2] [5 9 8 7 4 6] [13] 结束处理的必要条件必须满足: A[beginIndex - 1] <= min ,并且A[endIndex + 1] >= max 2 //书上解法错误,这里必须要判断找到的下标是否真的还符合题目要求;如果不符合,需要继续寻找下标 int flag = isCanFinish(datas , beginIndex , endIndex); while( 1 != flag) { //如果左边大于中间数组最小值,左边寻找到的下标减1,并继续判断 if( 2 == flag) { beginIndex--; flag = isCanFinish(datas , beginIndex , endIndex); } else if( 3 == flag) { endIndex++; flag = isCanFinish(datas , beginIndex , endIndex); } } 3 寻找数组 datas[low ... high]中的最小值和最大值,这里用分治法来做 分治法原理:将规模为n的子问题划分为k个规模较小的子问题,子问题独立,对子问题求解,并将答案合并 分治法本质是一种特殊地递归,一般可以通过二分法进行处理 分治法处理步骤:1)划分 , 2)处理 ,3)归并答案 如果low = high,表明只有一个元素,则最大值和最小值都是它 否则,令min = datas[low],max=datas[max]; 令middle = low + (high - low)/2; 得到 result1 = findMinAndMax(datas , low , middle); result2 = findMinAndMax(datas , middle+1 , high); min = result1.min < result2.min ? result1.min : result2.min; max = result1.max > result2.max ? result1.max : result2.max;
代码: bool isOrder(vector { if(datas.empty()) { return true; } int size = datas.size(); for(int i = 1 ; i < size ; i++) { if(datas.at(i) < datas.at(i-1)) { return false; } } return true; }
//寻找左边递增序列的截止位置 int findLeftIndex(vector { if(datas.empty()) { return -1; } int size = datas.size(); int i; for(i = 0 ; i < size - 1 ; i++) { if(datas.at(i) > datas.at(i+1)) { return i; } } return i; }
//寻找右边递增序列的截止位置 int findRightIndex(vector { if(datas.empty()) { return -1; } int size = datas.size(); int i; for(i = size - 1 ; i >= 1 ; i--) { if(datas.at(i) < datas.at(i-1)) { return i; } } return i; }
//寻找大于或小于value的下标 int findIndex(vector { //如果是寻找左边数组中,第一个比value小的下标 int i; int size = datas.size(); if(isFindLeft) { for(i = index ; i >= 0 ; i--) { if(datas.at(i) <= value) { return (i + 1); } } } else { for(i = index ; i < size ; i++ ) { if(datas.at(i) >= value) { return (i - 1); } } } return -1; }
/*寻找数组 datas[low ... high]中的最小值和最大值,这里用分治法来做 分治法原理:将规模为n的子问题划分为k个规模较小的子问题,子问题独立,对子问题求解,并将答案合并 分治法本质是一种特殊地递归,一般可以通过二分法进行处理 分治法处理步骤:1)划分 , 2)处理 ,3)归并答案 如果low = high,表明只有一个元素,则最大值和最小值都是它 否则,令min = datas[low],max=datas[max]; 令middle = low + (high - low)/2; 得到 result1 = findMinAndMax(datas , low , middle); result2 = findMinAndMax(datas , middle+1 , high); min = result1.min < result2.min ? result1.min : result2.min; max = result1.max > result2.max ? result1.max : result2.max; */ pair { int size = datas.size(); if(datas.empty() || low > high || high >= size) { pair return result; } //如果只有一个元素 if(low == high) { pair return result; } //如果有两个元素,注意是等于号 else if( high == low + 1) { int min = datas.at(low) < datas.at(high) ? datas.at(low) : datas.at(high); int max = datas.at(low) > datas.at(high) ? datas.at(low) : datas.at(high); pair return result; } //多个元素,二分后递归处理 { int realMin = INT_MAX; int realMax = INT_MIN; int middle = low + (high - low) / 2; pair pair //比较 realMin = result1.first < result2.first ? result1.first : result2.first; realMax = result1.second > result2.second ? result1.second : result2.second; pair return result; } }
//判断当前数组是否可以结束处理,即已经找到正确的下标,返回1:表示可以正确,返回2:表示左边不正确,返回3:表示右边不正确 int isCanFinish(vector { if(datas.empty() || beginIndex < 0 || endIndex >= datas.size() || beginIndex >= endIndex) { return 1; } pair int min = result.first; int max = result.second; //如果左边大于中间数组最小值 if(datas.at(beginIndex - 1) > min ) { return 2; } //如果右边小于中间数组最大值 else if(datas.at(endIndex + 1) < max) { return 3; } else { return 1; } }
pair { pair if(datas.empty()) { return invalidResult; } //检查数组是否有序,如果有序,直接返回 if(isOrder(datas)) { return invalidResult; } int leftIndex = findLeftIndex(datas); int rightIndex = findRightIndex(datas); pair int min = result.first; int max = result.second; int beginIndex = findIndex(datas , leftIndex , min , true) ; int endIndex = findIndex(datas , rightIndex , max , false); //书上解法错误,这里必须要判断找到的下标是否真的还符合题目要求;如果不符合,需要继续寻找下标 int flag = isCanFinish(datas , beginIndex , endIndex); while( 1 != flag) { //如果左边大于中间数组最小值,左边寻找到的下标减1,并继续判断 if( 2 == flag) { beginIndex--; flag = isCanFinish(datas , beginIndex , endIndex); } else if( 3 == flag) { endIndex++; flag = isCanFinish(datas , beginIndex , endIndex); } } pair return realResult; }
void process() { int num; vector int value; pair while(cin >> num) { datas.clear();//复用之前容器,数据要清空 for(int i = 0 ; i < num ; i++) { cin >> value; datas.push_back(value); } result = getIndexs(datas); cout << result.first << " " << result.second << endl; } } |
23 |
Remove Duplicates from Sorted Array Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. Do not allocate extra space for another array, you must do this in place with constant memory. For example, Given input array nums = [1,1,2], Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length. 分析: 此题就是删除数组中重复元素,应该可能和查找上下区间的函数有关。 要求不能分配额外空间到另外一个数组,花费常量空间。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54848253 |
24 |
Trapping Rain Water Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image! 分析: elevation map:高度图。此题实际上是根据给定的数组,画出高度图,然后计算出高度图中可以盛放的雨水。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54945828 |
25 |
Rotate Image You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). Follow up: Could you do this in-place? 分析: 这个是程序员面试经典的一道题目。题目本意是将n*n的矩阵顺时针旋转90度。 参见下图,主要想法是:将111旋转到222的位置,222旋转到333的位置,333旋转444的位置,444旋转到111的位置. 同理:将5旋转到6,6旋转到7,... 1112 4562 4872 4333 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54968136 |
26 |
Spiral Matrix Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. For example, Given the following matrix: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] You should return [1,2,3,6,9,8,7,4,5]. 分析: spiral order:螺旋顺序。题目意思就是将矩阵中的元素按照螺旋顺序输出。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54971784 |
27 |
Spiral Matrix II Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. For example, Given n = 3, You should return the following matrix: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 分析:蛇形矩阵问题,填充数字。填充1到n^2 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54974116 |
28 |
Set Matrix Zeroes Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. click to show follow up. 分析:这是程序员面试金典的一道题目。元素为0,需要将该元素所在行和列都置为0。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54991757 |
29 |
Search a 2D Matrix Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted from left to right. The first integer of each row is greater than the last integer of the previous row. For example, Consider the following matrix: [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] Given target = 3, return true. |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/54999532 |
30 |
Remove Duplicates from Sorted Array II Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For example, Given sorted array nums = [1,1,1,2,2,3], Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length. 分析:这次是如果有重复的元素,至少保留两个重复的元素。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/55006489 |
31 |
Longest Consecutive Sequence Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your algorithm should run in O(n) complexity. 分析:题目给定一个未排序的数组,需要找出最大连续序列,返回它的长度。 时间复杂度必须为O(n)。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/55310807 |
32 |
Maximum Product Subarray Find the contiguous subarray within an array (containing at least one number) which has the largest product. For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6. 分析:找到最大连续乘积的子数组,至少包含一个元素 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56021850 |
33 |
Rotate Array Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. Note: Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. [show hint] Related problem: Reverse Words in a String II 分析:等于将数组最右侧的元素旋转k次。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56292393 |
34 |
Happy Number Write an algorithm to determine if a number is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers. Example: 19 is a happy number 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1 分析:一个快乐的数被定义为将这个数的各个位上的数字拆分后的平方和到最后变成1,即可。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56319573 |
35 |
Summary Ranges
Given a sorted integer array without duplicates, return the summary of its ranges. For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"]. 分析:给定无重复的已经排序的数组,返回其整数范围 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56674406 |
36 |
Majority Element II
Given an integer array of size n, find all elements that appear more than ? n/3 ? times. The algorithm should run in linear time and in O(1) space. 分析:寻找向下取整,出现次数>=n/3的那个数字,只允许在O(n)时间, 空间O(1)范围内。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56678458 |
37 |
Product of Array Except Self Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. Solve it without division and in O(n). For example, given [1,2,3,4], return [24,12,8,6]. Follow up: Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the purpose of space complexity analysis.) 分析:题目给定了一个数组,返回一个结果数组,结果数组中任意元素的值等于输入数组中除了该下标对应元素外其他所有元素 的乘积。不允许用除法。时间复杂度在O(n),空间复杂度为常量空间。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56844551 |
38 |
Search a 2D Matrix II Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom. For example, Consider the following matrix: [ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ] Given target = 5, return true. Given target = 20, return false. 分析:给定一个矩阵,从左到右升序,从上到下升序。 寻找给定元素。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/56845496 |
39 |
Ugly Number II Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. Note that 1 is typically treated as an ugly number, and n does not exceed 1690. 分析:实际上是求第n个丑数,丑数从1开始。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/57075402 |
40 |
Move Zeroes Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. Note: You must do this in-place without making a copy of the array. Minimize the total number of operations. |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/57407918 |
41 |
Peeking Iterator Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that support the peek() operation -- it essentially peek() at the element that will be returned by the next call to next(). Here is an example. Assume that the iterator is initialized to the beginning of the list: [1, 2, 3]. Call next() gets you 1, the first element in the list. Now you call peek() and it returns 2, the next element. Calling next() after that still return 2. You call next() the final time and it returns 3, the last element. Calling hasNext() after that should return false. peek不是获取当前位置的元素,而是获取等同于执行下一次next操作的元素 而next操作是获取当前位置元素,并设置位置累加
|
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/57411783 |
42 |
Range Sum Query - Immutable Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. Example: Given nums = [-2, 0, 3, -5, 2, -1] sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3 Note: You may assume that the array does not change. There are many calls to sumRange function. 分析:给定一个数组,找到给定两个下标之间的所有元素的 和,包含两个下标。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/57420675 |
43 |
Range Sum Query 2D - Immutable Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2). Range Sum Query 2D The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8. Example: Given matrix = [ [3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5] ] sumRegion(2, 1, 4, 3) -> 8 sumRegion(1, 1, 2, 2) -> 11 sumRegion(1, 2, 2, 4) -> 12 Note: You may assume that the matrix does not change. There are many calls to sumRegion function. You may assume that row1 ≤ row2 and col1 ≤ col2. 分析:此题是求给定的矩阵中由左上角和右下角所划分的矩形中所有元素的和。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/57422731 |
44 |
Range Sum Query - Mutable Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val. Example: Given nums = [1, 3, 5] sumRange(0, 2) -> 9 update(1, 2) sumRange(0, 2) -> 8 Note: The array is only modifiable by the update function. You may assume the number of calls to update and sumRange function is distributed evenly. 分析:此题是需要统计范围区间的值,但是会修改某个下标。因此一旦进行更新操作,就会 需要重新统计范围的值 更新的index位置处的值,将会影响统计[i,j],其中 j >= index。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/58290971 |
45 |
Super Ugly Number
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4. Note: (1) 1 is a super ugly number for any given primes. (2) The given numbers in primes are in ascending order. (3) 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000. (4) The nth super ugly number is guaranteed to fit in a 32-bit signed integer. 分析:题目给定了一个长度为k的丑数列表,计算第n个丑数。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/58610314 |
46 |
Increasing Triplet Subsequence Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array. Formally the function should: Return true if there exists i, j, k such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false. Your algorithm should run in O(n) time complexity and O(1) space complexity. Examples: Given [1, 2, 3, 4, 5], return true. Given [5, 4, 3, 2, 1], return false. 分析:题目是让你判断未排序的数组中是否存在着长度至少为3的递增子序列。 算法运行时间为O(n),只允许使用常量空间。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/59108940 |
47 |
Intersection of Two Arrays Given two arrays, write a function to compute their intersection. Example: Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2]. Note: Each element in the result must be unique. The result can be in any order. 分析:给定两个数组,计算连个数组的交集,交集中的每个元素必须是唯一的。 结果可以是任何顺序。 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/59170671 |
48 |
Intersection of Two Arrays II Given two arrays, write a function to compute their intersection. Example: Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2]. Note: Each element in the result should appear as many times as it shows in both arrays. The result can be in any order. Follow up: What if the given array is already sorted? How would you optimize your algorithm? What if nums1's size is small compared to nums2's size? Which algorithm is better? What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once? 输入: 2(第一个数组元素个数) 2(第二个数组元素个数) 1 2 1 2 4 2 1 2 2 1 2 2 输出: 1 2 |
Leecode https://blog.csdn.net/qingyuanluofeng/article/details/59197123 |
49 |
如何找出数组中重复元素序列 对于一个给定的自然数N,有一个N+M个元素的数组,其中存放了小于等于N的所有自然数,求重复出现的自然数序列[X] |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/92079372 |
50 |
如何求解最小三元组距离 已知三个升序整数数组a[l], b[m]和c[n],请在三个数组中各找出一个元素,使得 组成的三元组距离最小,三元组距离的定义是: 假设a[i]、b[j]和c[k] 是一个三元组,那么距离为: Distance=max(|a[i] - b[j]|,|a[i] - c[k]|,|b[j] - c[k]|), 请设计一个求最小三元组距离的最优算法。 |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/92760447 |
51 |
如何对数组旋转 请实现方法: print_rotate_matrix(intmatrix, int n),该方法 用于将一个n*n的二维数组逆时针旋转45度后打印,例如,下图 显示一个3*3的二维数组及其旋转后屏幕输出的效果 1 2 3 4 5 6 7 8 9 从右上角遍历结果为: |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/92851467 |
52 |
如何对数组进行循环移位 把一个含有N个元素的数组循环右移K(K是正数)位,要求时间复杂度位O(N), 且只允许使用两个附加变量。
|
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/93158574 |
53 |
如何在有规律的二维数组中进行高效的数据查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 请实现一个函数,输入这样的一个二维数组和一个整数,判断数组中是否包含该整数。 例如下面的二维数组就是符合这种约束条件的。如果在这个数组中查找数字7, 由于数组中含有该数字,则返回True;如果在这个数组中查找数字5,由于数组中不含有 该数字,则返回False。 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/93396136 |
54 |
如何对磁盘分区 有N个磁盘,每个磁盘大小为D[i](i=0...N-1),现在要在这N个磁盘上 "顺序分配"M个分区,每个分区大小为P[j](j=0...M-1),顺序分配的意思是: 分配一个分区P[j]时,如果当前磁盘剩余空间足够,则在当前磁盘分配; 如果不够,则尝试下一个磁盘,直到找到一个磁盘D[i+k]可以容纳该分区, 分配下一个分区P[j+1]时,则从当前磁盘D[i+k]的剩余空间开始分配, 不在使用D[i+k]之前磁盘未分配的空间,如果这M个分区不能在这N个磁盘完全分配, 则认为分配失败,请实现函数 , is_allocable判断给定N个磁盘(数组D)和 M个分区(数组P),是否会出现分配失败的情况?举例: 磁盘为[120, 120, 120],分区为[60, 60, 80, 20, 80]可分配, |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/94123071 |
55 |
如何求有序数列的第500个数的值 一个有序数列,序列中的每一个值都能被2或者3或者5所整除,1是这个序列的第一个元素。求第1500个值是多少。 |
Python程序员面试算法宝典 https://blog.csdn.net/qingyuanluofeng/article/details/96564589 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
参考:
[1]计算机考研--机试指南,王道论坛 组编
[2]剑指offer
[3]算法设计与分析
[4]编程之美
[5]程序员面试金典
[6]leecode
[7]Python程序员面试算法宝典
[8]刘汝佳算法竞赛入门经典
[9]算法导论
[10]编程珠玑