public class Singleton {
private static Singleton singleton;
// 注意点: 私有化构造函数
private Singleton() {
}
// synchronized 多线程环境
public synchronized static Singleton getInsatnce() {
if(singleton==null) {
singleton = new Singleton();
}
return singleton;
}
}
/** 参考思路
1. 遍历一次字符串,得到空格的总数,以及数组的总长度
2. 创建一个新字符数组,长度为原字符串长度 + 空格个数 * 2
3. 两个指针,P1指向原字符数组末尾,P2指向新字符数组的末尾
4. 移动P1,若非空格,复制至新字符串数组,若为空格,P2插入%20
分析
时间复制度为O(n)
*/
/**
遍历链表至栈中,因为栈为“后进先出”
*/
// 二分查找 O(logn)
/**
* 把一个整数减1之后,再与原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0
*/
// 代码需要完备
// 当指数为负数,底数为0等
// 当n很大时,会溢出
// 可考虑用字符串表示数字
// 思路:把需删除结点的下一个结点内容复制到需删除的结点上,再把下一个结点删除
0011 调整数组顺序使奇数位于偶数前面
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分
参考答案
/** 1. 维护两个指针,P1指向数组的第一个数字,向后移动; P2指向数组的最后一个数字,向前移动。 2. 在指针相遇前,若P1指向数字是偶数,P2指向数字是奇数,则交换这两个数字 3. 把比较的逻辑部分抽取出来,实现解耦,以满足更多的比较,如把所有的负数放在非负数前面,能被3整除的数放在不能被3整除的数前面 4. 代码扩展性,可重用性 */
0012 链表中倒数第K个结点
题目:输入一个单向链表,输出该链表中倒数第k个结点
/** 1. 两个指针P1,P2 2. P1从链表头向前遍历走k-1,P2不变 3. 第k步,P1,P2一起移动,当P1到达尾结点时,P2正好是倒数第k个结点 */
0013 求链表的中间结点
题目:如果链表中结点总数为奇数,返回中间结点;如果结点总数是偶数,返回中间两个结点的任意一个
/** 1. 类同0012,定义两个指针P1,P2 2. 遍历链表,P1走一步,P2走两步,当P2至达末尾时,P1正好在链表的中间 */
0014 判断一个单向链表是形成了环形结构
题目: 判断一个单向链表是形成了环形结构
1. 类同0013,定义两个指针P1,P2 2. 遍历链表,P1走一步,P2走两步,如果走的快的追上了走的慢的,则为环形链表 3. 如果P2走到了链表末尾,仍没有追上P1,则不是环形链表
0015 反转链表
题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点
/** * 为防止链表断开,需要保存结点 */
0016 合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的
0017 树的子结构
题目:输入一棵二叉树A和B,判断B是不是A的子结构。
0018 二叉树的镜像
题目:请完成一个函数,输入一个二叉树,输出它的镜像
```Java /* 前序遍历树的每个结点 * 如果遍历到的结点有子结点,则交换子结点 * 当交换完所有非叶子结点的左右子结点后,就得到了树的镜像 */ public void mirrorRecursively(BinaryTreeNode binaryTreeNode) { if(binaryTreeNode==null || (binaryTreeNode.leftNode==null && binaryTreeNode.rightNode==null) ) { return; }
BinaryTreeNode tempNode=binaryTreeNode.leftNode; binaryTreeNode.leftNode=binaryTreeNode.rightNode; binaryTreeNode.rightNode=tempNode; // 递归 mirrorRecursively(binaryTreeNode.leftNode); mirrorRecursively(binaryTreeNode.rightNode);
}
# 0019 包含min函数的栈 ## 题目:定义栈的数据结构,实现一个得到栈最小值的min函数。使得调用min,push及pop的时间复杂度都为O(1). ## 参考答案
Java /* 采用辅助栈,将最小值压入辅助栈中 */ ```0020 栈的压入,弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字都不相等。如序列1,2,3,4,5为压栈序列,序列4,5,3,2,1为该压栈序列对应的一个弹出序列,但4,3,5,1,2不是该压栈序列的弹出序列
/** * 如果下一个弹出的数字刚好是栈顶数字,直接弹出 * 如果下一个弹出的数字不在栈顶,把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止 * 如果所有的数字都压入栈了,仍然没有找到下一下弹出的数字,那么该序列不可能是一个弹出序列 */
0031 归并排序MergeSort
题目:请写出归并排序
参考答案
```Java package com.javamm.al.sort;
/** * * 算法复杂度O(nlogn),冒泡,插入,选择都需要O(n2),若n为10000,n平方100000000,nlogn为40000,若归并需要40s, * 则插入排序需要28h 缺点:需要在存储器有另一个大小等于被排序的数据项目的数组,即要足够的空间 思想:归并两个有序的数组 * 注意:类名请写成MergeSort */ public class MergeSort {
public static void recSort(int[] data, int left, int right) { System.out.println("recSort,left:" + left + " right:" + right); if (left == right) { return; } int center = (left + right) / 2; // 递归左边 recSort(data, left, center); // 递归右边 recSort(data, center + 1, right); // merge merge(data, left, center, right); } public static void merge(int[] data, int left, int center, int right) { System.out.println("merge,left:" + left + " center: " + center + " right: " + right); int[] tmpData = new int[data.length]; int mid = center + 1; int third = left; int tmp = left; while (left <= center && mid <= right) { if (data[left] <= data[mid]) { tmpData[third++] = data[left++]; } else { tmpData[third++] = data[mid++]; } } while (mid <= right) { tmpData[third++] = data[mid++]; } while (left <= center) { tmpData[third++] = data[left++]; } // 将tmpData中的内容复制回原数组 while (tmp <= right) { data[tmp] = tmpData[tmp++]; } } public static void main(String[] args) { int[] data = { 3, 2, 1, 6, 0, 8 }; recSort(data, 0, data.length - 1); for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " ,"); } }
}
# 0032 QuickSort ## 请写出快速排序 ## 参考答案
Java /* 思想: * 1. 一躺排序将要排序的数据分成独立的两部分,一部分比另一部分所有数据都小,可用两指针,leftP,rightP,分别指向首尾 * 2. 再按此方法对这两部分数据进行排序,可用递归 * * 算法复杂度: * * 最坏情况算法复杂度:O(n2),最好O(nlogn) */ public class QuickSort {private static int[] a; public static void main(String[] args) { a = new int[] { 5, 3, 2, 1, 8, 4 }; recQuickSort(0, a.length - 1); display(); } public static void recQuickSort(int left, int right) { // Step 1 :把数组划分成左边和右边,左边比选定的值小,右边比选定的值大 // Step 2 : 递归调用左边 // Step 3 : 递归调用右边 if (left >= right) { return; } int pivot = a[right]; int partition = partitionIt(left, right, pivot); recQuickSort(left, partition - 1); recQuickSort(partition + 1, right); } public static int partitionIt(int left, int right, int pivot) { display(); // 左指针 int leftP = left - 1; // 右指针 int rightP = right; while (true) { // 左边的值都比pivot小时 while (a[++leftP] < pivot) ; // 右边的值都比pivot大时 while (rightP > 0 && a[--rightP] > pivot) ; if (leftP >= rightP) { break; } else { // 交换 swap(left, right); } } swap(leftP, right); return leftP; } public static void swap(int left, int right) { int temp = a[left]; a[left] = a[right]; a[right] = temp; } public static void display() { for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } System.out.println(""); }
}
```
0033 HeapSort
参考答案
/** * * 若一个数组节点的索引为x * * 其父节点的下标为(x-1)/2 * * 左子节点下标为2*x +1 * * 右子节点下标为2*x + 2 * */
层次遍历二叉树
题目:写一个函数,层次遍历二叉树
参考答案
/** * 思路:每打印一个结点的时候,如果该结点有子结点,将子结点放入队列末尾 */
字符串的排列
题目:输入一个字符串,打印出该字符串中字符的所有排列。如输入abc,则输出acb,bac,bca,cab,cba
参考答案
Java /** * 将字符串分为两部分,一部分是字符串的第一个字符,另一部分是第一个字符外所有字符 * 用递归 */
# 字符串的所有组合 ## 题目:输入一个字符串,打印出该字符串中字符的所有组合。如输入abc,则输出a,b,c,ab,ac,bc,abc,注,ab,ba是不同的排列,但只算一个组合Java /** * 输入n个字符,则能构成长度为1,2,...n的组合 * 求n个字符长度为m的组合的时候,把m个字符分为两部分,第一个和m-1个,递归 */
# 正方体所有面之和相等 ## 输入一个含有8个数字的数组,判断有没有可能这8个数字分别放到正方体的8个顶点上,使得每一面的顶点之和都相等。Java /** * 如输入a1,a2,a3,a4,a5,a6,a7,a8,求所有排列,看是否满足条件,a1+a2+a3+a4==a5+a6+a7+a8,a1+a3+a5+a7=a2+a4+a6+a8,并且a1+a2+a5+a6=a3+a4+a7+a8 */
# 0029 数组中出现次数超过一半的数字 ## 题目:数组中有一个数字出现的次数超过了数组长度的一半,请求出这个数字。如{1,2,3,2,2,2,5,4,2},此数字为2Java /** * 思路一:排序,排好序后,求中间数字 * 根据快排思想,先随机选一个数字,使比他小的都排在左边,比他大的都排右边。完成后,若此数字下标为n/2,即为此数。如果下标> n/2,那么此数位于左边,可在左半部查找,用递归。否则位于右边 * 思路二: * 遍历数组时,保存两个值,一个为数组中数字,一个为次数 * 当遍历下一个数字时,若与保存数字相同,次数+1.若与保存数字不同,次数-1,若次数=0,重新保存新数字,并将次数设为1.最后一次把次数设为1的数字即为所需的数字 * eg: * 1,1 * 2,1 * 3,1 * 2,1 * 2,2 * 2,3 * 2,2 * 2,1 * 2,2 */
# 0030 求一个数组的第k小的数 ## 题目:给定一个无序整数数组,返回这个数组中第k小的数 ```Java /* 思路一: * 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1)。使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n)。
* * 思路二: * 维持一个大小为k的大顶堆,遍历一次数组,如果数组中的元素比堆顶的元素小,那么就更新堆。最后堆中存放的是数组中的前k小元素。堆顶元素即为要求的第k小个数。
# 0031 连续子数组的最大和 ## 题目:输入一个整数型数组,数组中有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值
Java /**