1、调整数组顺序使奇数位于偶数前面(并实现一个快速排序,对结果进行排序)
题目:输入一个整数数组,实现一个函数来调整该函数数组中数字的顺序,使得
所有奇数位于数组的前半部分,所有的偶数位于数组的后半部分。
2、斐波那契数列
写一个函数,输入 n,求斐波那契数列的第 n 项。(两种方法实现,一种是数组,一种是用一个中间值去保存)
3、两个栈实现一个队列的入队和出队
4、查找旋转数组中最小的元素
题目大致为:
一个递增排序的数组的一个旋转(把一个数组最开始的若干元素搬到数组的末尾,称之为数组的旋转),输出旋转数组的最小元素。
思路:
其实旋转过后的数组是部分有序的,这样的数组依然可以使用折半查找的思路求解
5、输入链表中倒数第K个元素的值
题目大致为:
在一个链表中,查找倒数的第k个数。
思路:
使用双指针的方式,前一个指针先走k步(中间隔k-1个结点),后一个指针才开始走,直到第一个指针走到尾,后一个指针指向的就是要找的倒数第k个数。值得注意的是:1、k是否超过链表长度且k必须为正整数;2、链表是否为空。
链表结构
6、链表的反转
题目大致为:
对于一个链表,反转该链表并返回头结点。
思路:
主要是指针的操作,但是要注意不能断链。这里可以使用非递归的方式求解。
链表结构
(1)用栈去操作
(2)用三个指针去操作,指向前一个节点、中间一个节点、后面一个节点
7、统计数组中出现次数超过一半的数
题目大致为:
数组中有一个数字出现的次数超过数组长度的一般,找出这个数字。
思路:
在遍历数组的过程中纪录两个量,一个是数组中的数字,一个是次数,当下一个数字和我们保存的一致时则次数加1,当不一致时次数减1,当次数为0时,重置两个量。数组中的数字为当前访问的值,次数为1。这里主要是利用了出现的次数超过了一半,其实就是超过一半数出现的次数减去其他的数出现的次数始终是大于0的。
Java实现
8、最小的K个数
题目大致为:
输入n个整数,找出其中最小的k个数。
思路:
使用类似二叉查找树的形式实现,控制好树中的结点个数为k。
Java代码
9、求连续子数组的最大值
题目大致为:
输入一个整型数组,数组里有正数也有负数。数组中一个或者连续的多个整数组成一个字数组。求所有字数组的和的最大值。要求时间复杂度为O(n)。
思路:
因为时间复杂度为O(n),则只能遍历一次数组,这里同时使用两个变量currentSum和finalGreatSum,其中currentSum保存的是当前的和,若currentSum<0,则从下一个位置从新记录,finalGreatSum记录的是历史的最小值,只有当currentSum>finalGreatSum时用currentSum替换finalGreatSum。
Java代码
10、第一个只出现一个的字符
题目大致为:
在字符串中找出第一个只出现一次的字符。
思路:
在Java中可以把字符串转换成字符数组处理,可以使用HashMap的数据结构存储,其中key为字符,value为对应出现的次数,这样通过两次遍历字符数组就可以找出,其中,第一次是构建HashMap,第二次是对每个字符判断其HashMap中对应的value的值是否为1。
Java实现
11、两个链表的第一个公共结点
题目大致为:
输入两个链表,找出它们的第一个公共结点。
思路:
第一个公共结点开始往后都是公共结点,所以在末尾向前遍历,就可以找到第一个公共结点。利用上面的思想,可以先计算两个链表的长度,计算两个链表的长度差,然后先遍历较长的链表,等到剩余长度相等时开始同时遍历,这样就能较快地找到相同的结点,时间复杂度为O(m+n),其中m,n分别为两个链表的长度。
Java实现
12、二维数组中的查找
题目大致为:
一个二维数组,每一行按照从左到右递增,每一列按照从上到下递增,查找数组中是否存在某个数。如数组:
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
思路:
这道题有其特殊性,从右上角或者左下角开始查找的方向是确定的。这句话是说比如是查找7,我们从右上角开始,9大于7,则减少列下标,查找13的话就增加行下表,查找的方向是确定的,这样就容易实现了。
Java代码:
13、数字在排序数组中出现的次数
题目大致为:
统计一个数字在排序数组中出现的次数。
思路:
解法一:遍历数组,把每个元素出现的次数保存在HashMap中,数组元素当做key,出现的次数当做value,然后在HashMap中获取这个num出现的次数并输出
解法二:因为是顺序排序的数组,利用二分查找,找到目标元素第一次出现的位置和最后一次出现的位置,直接在这个区间内找这个元素出现的次数即可。
14、反转单词的顺序
题目一大致为:
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。
思路:
两次翻转,对于字符串"I am a student.",首先进行第一次翻转,即翻转完为:".tneduts a ma I",然后再对每个单词翻转,最终为:"student. a am I"。
Java实现
15、通过一系列的栈的压入和弹出操作来分析用队列模拟一个栈的过程,如图所示,我们先往栈内压入一个元素a。由于两个队列现在都是空,我们可以选择把a插入两个队列中的任一个。我们不妨把a插入queue1。接下来继续网栈内压入b,c两个元素。我们把它们都插入queue1。这个时候 queue1包含3个元素a,b,c其中a位于队列的头部,c位于队列的尾部。
现在我们考虑从栈内弹出一个元素。根据栈的后入先出的原则,最后被压入栈的c应该最先被弹出。由于c位于queue1的尾部,而我们每次只能从队列的头部删除元素,因此我们可以从queueu中依次删除a/b/c并插入到queue2中,再从queue1中删除c。这就相当于从栈中弹出元素c了。我们可以用同样的方法从栈内弹出元素b。
接下来我们考虑从栈内压入一个元素d.此时queue1已经有了一个元素,我们就把d插入到queue1的尾部。如果我们再从栈内弹出一个元素,此时被弹出的应该是最后被压入的d.由于d位于queue1的尾部,我们只能先从头部删除 queue1的元素并插入到queue2,直到queue1中遇到d再直接把它删除。如图所示:
16、题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能。
我们通过一个具体的例子来分析该队列插入和删除元素的过程。首先插入一个元素a,不妨先把它插入到stack1,此时stack1 中的元素有{a},stack2为空。再压入两个元素b和c,还是插入到stack1中,此时stack1中的元素有{a,b,c},其中c位于栈顶,而stack2仍然为空。
这个时候,我们试着删除从队列中删除一个元素。按照队列先入先出的规则,由于a比b、c先插入到队列中,最先被删除的元素应该是a。元素a存储在stack1中,但并不在占顶上,因此不能直接被删除。注意到stack2我们还一直没有使用过,现在是让stack2发挥作用的时候了。如果我们把stack1中的元素逐个弹出并压入stack2,元素在stack2中的顺序正好和原来的stack1中的顺序相反。因此经过3次弹出stack1和压入stack2操作之后,stack1为空,而stack2中的元素是{c,b,a},这个时候就可以弹出stack2的栈顶a了。此时的stack1为空,而stack2的元素为{c,b},其中在栈顶,如图所示: