剑指offer题解
2 实现Singleton模式
题目: 设计一个类,我们只能生成该类的一个实例
饿汉式,懒汉式,DCL懒汉式,静态内部类,枚举
建议的方法:
//枚举,天然一个对象,最佳完美,不用担心反射
public enum Singleton{
INSTANCE;
public Singleton getInstance(){
return INSTANCE;
}
}
//静态内部类
public class Singleton{
private Singleton(){}
private static class InnerClass{
private static final Singleton instance =new Singleton;
}
public static Singleton getInstance(){
return InnerClass.instance;
}
}
3-1 数组中重复的数字
- 排序 然后找,时间复杂度 nlogn ,空间0;
- hash表 时间 n,空间 n
- 每遍历数组中的一个数字,就让其归位(放置在正确的数组下标)。当在归位的过程中,发现该数组下标所存放的数字和当前要归位的数字相同时,则发生了重复,返回该数字。空间复杂度O(1),时间复杂度O(n)。
public class FindDuplicateNum_3 {
public static boolean findDuplicateNum(int[] arr, int length, int[] dup) {
if (arr == null || length <= 0) {
return false;
}
//时间复杂度O(n)
for (int i = 0; i < length; i++) {
//每个数字最多交换2次
while (arr[i] != i) {
if (arr[i] == arr[arr[i]]) {
dup[0] = arr[i];
return true;
}
swap(arr, i, arr[i]);
}
}
return false;
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
3-2 不修改数组找出重复数字
- 复制一个数组按照上面的方法,时间n,空间n
- 思路:将1~ n上的数字划分成两块:1~ m和m+1~ n,然后统计数组中该区间上的数字个数,如果数字个数大于区间长度,则发生了重复,然后在该区间上继续二分,直至区间长度等于1。时间nlongn ,空间0
- 写前搞懂面试官要什么,第二种是空间环时间
//不修改数组找出重复数字
public static int findDuplicateNumNoEdit(int[] arr, int length) {
if (arr == null || length <= 0) {
return -1;
}
int start = 1;
int end = length - 1;
while (start <= end) {
int mid = start + ((end - start) >> 1);
int count = getCount(arr, length, start, mid);
//System.out.println(mid+" "+count);
if (start == end) {
if (count > 1) {
return start;
} else {
return -1;
}
}
if (count > (mid - start + 1)) {
end = mid;
} else {
start = mid + 1;
}
}
return -1;
}
private static int getCount(int[] arr, int length, int start, int end) {
int count = 0;
for (int i = 0; i < length; i++) {
if (arr[i] >= start && arr[i] <= end) {
count++;
}
}
return count;
4 二维数组查找
从左下或者右上角开始查找,每次判断可以剔除一行或者是一列,时间复杂度O(n+m)
- 注意索引越界问题
//二维数组中找数,每行从小到大,每列从小到大
public class P04FindOrderMatrix {
//从左下或者右上开始,每次课排除一行或者一列
//从右上角开始找
public static boolean findOrderMatrix(int target,int[][] matrix){
int column =matrix[0].length -1;
int row =0;
while (column>=0 && row<= matrix.length-1) {
if (matrix[row][column] ==target){
return true;
}
else if (matrix[row][column] < target) {
row++;
} else {
column--;
}
}
return false;
}
}
5 替换空格
String 类有个replaceAll 的方法,用正则课替换
②显然是让自己写一个方法,时间复杂度要求bigO(n) ,利用额外的字符数组
public static String replaceBlankSpace2(String str){
//特殊情况
if (str==null|| str.length()<1){
return null;
}
//计算空格的数量
int count =0;
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i]== ' '){
count ++;
}
}
//new一个新的字符数组,长度是原数组的长度+空格数的二倍
char[] res = new char[chars.length+ 2*count];
int resl =res.length-1;
int charl =chars.length -1;
//从后往前拷贝即可
for (int i =charl; i >= 0; i--) {
if (chars[i] !=' ' ){
res[resl--] = chars[i];
}else{
res[resl--] ='0';
res[resl--] ='2';
res[resl--] ='%';
}
}
return String.valueOf(res);
}
6 从尾到头打印链表
- 用额外的空间,Stack的本质就是一个顺序的逆序
- 不用额外的空间,把链表翻转,打印再翻转回来
- 提示 面试时最好先问情况,能不能修改数据
public class FromHeadtoTailPrintLinkedList {
static class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public static void fromHeadtoTailPrintLinkedListByStack(ListNode head) {
if (head == null) {
return;
}
Stack<ListNode> stack = new Stack();
while (head != null) {
stack.push(head);
head = head.next;
}
while (!stack.isEmpty()) {
System.out.print(stack.pop().val + " ");
}
}
public static void fromHeadtoTailPrintLinkedListByRecursion(ListNode head) {
if (head == null) {
return;
}
fromHeadtoTailPrintLinkedListByStack(head.next);
System.out.print(head.val + " ");
}
}