# 这两天通过做作业接触了《剑指offer》 这本书;觉得里面的面试题真是异常经典,当你看到那一道一道面试题时,对自我的做题笔试能力肯定会大有脾益!
# 平常可以多做练习,养成一个习惯!好了,废话不多说了,直接上题吧! 我已经感到饥渴难耐了!
# 第一道:
/*剑指offer 面试题14:调整数组使奇数全部都位于偶数前面。
题目:
输入一个整数数组,实现一个函数,
来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,
所有偶数位于数组的后半部分。*/
首先,刚看到这道题的时候我是挺没有头绪的(可能是因为大早上刚睡醒),于是思考着题,在本子上画了画,
第一步: 肯定要把偶数判别一下,那很简单了, 大家都知道 除2余0即为偶数!
第二步: 怎样把偶数放到后面,奇数放在前面, 暂时只想到交换;即是偶数就和最后面的数交换,下一个偶数和倒数
第二个数交换;最后肯定会相遇,即循环结束!
第三步: 思路是有了,接下来就是代码的实现了(一些细微的优化在算法中实现)!
代码:
#include<stdio.h>
#include<stdlib.h>
void Int_sort(unsigned int arr[],int sz)
{
/*既然要前后交换就不妨设置两个指针一前一后相对运动*/
unsigned int *left = arr;
unsigned int *right = arr + sz -1;//这块的经常会有人忘记减一;
if(arr == NULL || sz == 0)//对数组的判空是很有必要的;
return ;
while(left < right)//循环结束条件,即前后指针相遇,结束循环;
{
/*left指向的数如果是奇数则继续指向下一个数,直至遇到偶数或者前后
指针相遇;*/
while((*left)%2 && (left < right))
{
left++;
}
if(!(*left%2))
{
int tmp = 0;
/*这其实是个小小的优化,如果right所指向的数是偶数;
则right向前移动,省去不必要的循环!*/
while(left<right && !*right%2)
{
right--;
}
/*left指向的数是偶数并且right指向的数是奇数则交换*/
tmp = *left;
*left = *right;
*right = tmp;
right--;
}
}
}
int main()
{
int i = 0;
/*测试的数组内容一定要考虑多种情况*/
unsigned int arr[] = {1,2,3,4,5,6,7,8,9,12,0,-2};
int sz = sizeof(arr)/sizeof(arr[0]);
Int_sort(arr,sz);
for(i = 0; i<sz; i++)
{
printf("%d ",arr[i]);
}
system("pause");
return 0;
}
/* 在剑指offer 将这个面试题时提到: 面试官可能会问你,如果是把负数放在非负数前面,或者可以被三整除的放在不
能被三整数的数的前面,那你该怎么办?
同样,重新写个函数,重新在把方法实现一变? (我的第一反应也是这样,还差得很远;),当然不可否认这种方法
是正确的,但是这并不是面试官想听到的答案; 这个时候应该冷静的想一想, 还可以怎么优化,可以方便一点, 不
知道你有没有想到 qsort 这个函数或者 冒牌排序 可以排序字符串数组 也可以排序 整数数组的方法; 对,就是利用函
数指针处理多种情况,但是在这里不作解释,将在关于函数指针和指针函数的博客中指出! */
http://blog.csdn.net/bitboss/article/details/51307175(博客链接,讲解函数指针)
#第二道:
/* 剑指offer 面试题3:
有一个二维数组.
数组的每行从左到右是递增的,每列从上到下是递增的.
在这样的数组中查找一个数字是否存在。
时间复杂度小于O(N) ; */
首先我的实现算法和剑指offer 大体一致,唯一的区别在于,剑指offer上对于二维数组直接当作一维数组来实现,当
然,多维数组在内存中的排列和以为数组一样,是连续开辟的,我们所想象的一行一行的只是为了我们便于理解,我
就不在这里做过多的强调了;
第一步: 你要操作二维数组,那么肯定封装函数实现吧,在这里传参就必然了,那么二维数组传参形式你就得靠清楚
了,arr[][4],和(*arr)[4],都可以接收;
第二步: 其实顺序有点乱啊,应该先思考算法的,,,,
,那么我们来想想,在二维数组中找出一个数,是不是
挺简单啊,只需要遍历就可以了,可是题目要求时间复杂度为0(N);那莫我们就得认真考虑了,这个二维数组是有
规律的,从左到右递增,自上而下递增,那么方法是不是就有了,我们每次用右上角的数字和目标数字比较,每次就
可以排除一行或者一列了!;
代码:
#include<stdio.h>
#include<stdlib.h>
int Number_sort(int (*arr)[4]/*arr[][4]也可以*/,int row,int col,int num)
{
int found = 0;//设置一个标志位,表示数字是否找到!
int rows = 0;//刚开始需要操作的行标,列标;
int cols = col - 1;
//循环的终止条件即为达到最后一行或者找到这个数;
while(rows < row && cols >= 0)
{
if(num == arr[rows][cols])
{
found = 1;
break;//找到立即结束循环;
}
else if(num > arr[rows][cols])
rows++;//目标大于右上角即排除一行;
else
cols--;//否则小于排除一列;
}
return found;
}
int main()
{
int arr[][4] = {{1,2,3,4},{2,3,4,5},{3,4,5,6},{4,5,6,7}};
int num = -1;
int row = sizeof(arr)/sizeof(arr[0]);//四行,即四个一维数组;
int col = (sizeof(arr)/sizeof(arr[0][0]))/row;//4列
printf("%d\n",Number_sort(arr,row,col,num));
system("pause");
return 0;
}
/* 这道题的实现并不难,难得是想到算法,对于我这种天资并不聪慧的只有多练,看到的多了,算法也就懂得多了*/
# 第三道:
/*剑指offer 面试题35:
一个字符串中查找第一个只出现一次的字符。
要求复杂度为O(N).
例如:
字符串:"aaaabfqccrbddw",返回f.*/
首先,我一看到这道题的第一想法便是遍历一遍找出只出现一次的字母,提前定义一个字符数组保存count==1的字
符,输出这个数组的第一个元素既为第一个只出现一次的字母,这种方法是可行的,在以前做的一道题里,在一个整
形数组中找只出现一次的数字,我就是这样用计数器这样做的,有兴趣的同学可以实现一下,我在这里只实现剑指offer
的哈希表算法(我自己觉得和我的算法大同小异);
第一步: 适当了解什么是哈希表,当然在这道题里只是用了最简单的哈希表,我也不做重点介绍了, 在这道题,所
谓哈希表就是定义一个 大小为256 的数组,因为字符的ASCLL码是0-255; 字符串中的每个字符的ASCLL码对应数
组的下标,即str[ a ];
第二步:先通过一个循环将字符串中出现的字符对应的 ASCLL 码下标的数组内容置为 字符出现的次数;时间复杂度
为O(N);再通过一个循环遍历 哈希表中找出第一个 内容为 1 的数组下标并返回对应字符!对哈希表的遍历时间复杂
度也是O(N);所以总的时间复杂度是O(N);(感觉有点牵强啊
);
第三步: 接下来就是代码的实现:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
char FoundOnlyOnceChar( char *arr)
{
int str[256] = {0};//对哈希表的初始化都为0初始时默认所有字符出现次数为0
char *p = arr;//保存初始位置,为第二次循环提供;
while(*arr)
{
str[*(arr++)]++;//第一次循环找出每个字符的出现次数;并以字符对应ASCLL作为下标;
}
while(*p)//第二次循环,通过字符串遍历哈希表找出第一个出现一次的字符;
{
if(str[*p] == 1)
return *p ;
p++;
}
return '\0';//如果没有出现一次的字符则返回‘\0’;
}
int main()
{
char *arr = "aaaabfqccrbddw";
printf("%c\n",FoundOnlyOnceChar(arr));
system("pause");
return 0;
}
代码比较粗糙,还望各位多多指出问题!
谢谢!