剑指offer题解02-10
02 单例模式
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
从具体实现角度来说,主要有三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
// 懒汉式-线程不安全
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
// 双重校验锁-线程安全
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
// 静态内部类实现
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
03 数组中重复的数字
/**
* 03 数组中重复的数字
* 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道 有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
*/
public class _03 {
public static boolean duplicate(int[] numbers,int length,int[] duplication) {
int [] array = new int[length];
for (int i = 0; i < length; ++i) {
if (array[numbers[i]] == 0) {
array[numbers[i]] = 1;
} else {
duplication[0] =numbers[i];
return true;
}
}
return false;
}
public static void main(String[] args) {
int[] numbers = {2, 3, 1, 0, 2, 5, 3};
int[] duplication = new int[1];
System.out.println(duplicate(numbers, numbers.length, duplication) + " " + duplication[0]);
}
}
04 二维数组中的查找
/**
* 04 二维数组中的查找
* 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
*/
public class _04 {
public static boolean find(int target, int [][] array) {
if (array == null || array.length == 0) {
return false;
}
if (array[0].length == 0) {
return false;
}
int col = array[0].length;
int row = array.length;
int i = row - 1;
int j = 0;
while (j < col && i >= 0) {
if (array[i][j] == target) {
return true;
} else if (array[i][j] > target) {
i--;
} else {
j++;
}
}
return false;
}
public static void main(String[] args) {
int[][] array = {{1, 4, 7, 11, 15},
{2, 5, 8, 12, 19}};
System.out.println("Find(5, array) = " + find(5, array));
}
}
05 替换空格
/**
* 05 替换空格
* 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过 替换之后的字符串为We%20Are%20Happy。
*
* 在字符串尾部填充任意字符,使得字符串的长度等于替换之后的长度。因为一个空格要替换成三个字符 (%20),因此当遍历到一个空格时,需要在尾部填充两个任意字符。
* 令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。P1 和 P2 从后向前遍历,当 P1 遍历到一个空格时,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),否则就填充上 P1 指向字符的值。
* 从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容
*/
public class _05 {
public static String replaceSpace(StringBuffer str) {
int originalLength = str.length();
for (int i = 0; i < originalLength; ++i) {
if (str.charAt(i) == ' ') {
// 每遇到一个空格扩充2个长度
str.append(" ");
}
}
int newLength = str.length();
int j = newLength - 1;
for (int i = originalLength - 1; i >= 0; --i) {
if (str.charAt(i) == ' ') {
str.setCharAt(j--, '0');
str.setCharAt(j--, '2');
str.setCharAt(j--, '%');
} else {
str.setCharAt(j--, str.charAt(i));
}
}
return str.toString();
}
public static void main(String[] args) {
replaceSpace(new StringBuffer("We Are Happy"));
}
}
06 从头到尾打印链表
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* 06 从头到尾打印链表
* 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
*/
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
public class _06 {
/**
* 使用堆栈
* @param listNode 链表头结点
* @return 反向打印所有值
*/
public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if (listNode == null) {
return new ArrayList<>();
}
Stack<Integer> stack = new Stack<>();
ArrayList<Integer> arrayList = new ArrayList<>();
while (listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
while (!stack.empty()) {
arrayList.add(stack.pop());
}
return arrayList;
}
/**
* 使用递归
* @param listNode 链表头结点
* @return 反向打印所有值
*/
public static ArrayList<Integer> printListFromTailToHead1(ListNode listNode) {
if (listNode == null) {
return new ArrayList<>();
}
ArrayList<Integer> arrayList = printListFromTailToHead1(listNode.next);
arrayList.add(listNode.val);
return arrayList;
}
/**
* 使用头插法
* 构建一个头指针head,初始head->next = null,然后不断将listNode中的节点加到head后 面,相当于反向链表
* @param listNode 链表头结点
* @return 反向打印所有值
*/
public static ArrayList<Integer> printListFromTailToHead2(ListNode listNode) {
if (listNode == null) {
return new ArrayList<>();
}
// 头指针
ListNode head = new ListNode(0);
head.next = null;
// 将listNode中的结点逐步加到head后面
while (listNode != null) {
// 先存储下一个结点
ListNode nextNode = listNode.next;
// 头插
listNode.next = head.next;
head.next = listNode;
// 继续下一次循环
listNode = nextNode;
}
ArrayList<Integer> arrayList = new ArrayList<>();
// 头结点
listNode = head.next;
while (listNode != null) {
arrayList.add(listNode.val);
listNode = listNode.next;
}
return arrayList;
}
public static void main(String[] args) {
// 构造一个链表
ListNode listNode1 = new ListNode(1);
ListNode listNode2 = new ListNode(2);
listNode2.next = null;
listNode1.next = listNode2;
List<Integer> list = printListFromTailToHead2(listNode1);
for (Integer integer : list) {
System.out.println(integer + " ");
}
}
/**
* 内部类:相当于一个链表节点
*/
public static class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
}
07 重建二叉树
/**
* 07 重建二叉树
* 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结 果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列 {4,7,2,1,5,3,8,6},则重建二叉树并返回。
* 前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序 遍历结果,右部分为树的右子树中序遍历的结果,然后就可以接着分别对左右子树递归下去。
*/
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class _07 {
/**
* 重建二叉树
* @param pre 前序遍历
* @param in 中序遍历
* @return 返回重建的二叉树
*/
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if (pre == null || in == null || pre.length == 0 || in.length == 0) {
return null;
}
return reConstructBinaryTree(pre, in, 0, pre.length - 1, 0, in.length - 1);
}
/**
* 扩充前序与中序的索引参数,便于递归重建二叉树
* @param pre 前序遍历
* @param in 中序遍历
* @param preStart 前序遍历数组的开始索引
* @param preEnd 前序遍历数组的结束索引
* @param inStart 中序遍历数组的开始索引
* @param inEnd 中序遍历数组的结束索引
* @return 返回重建的二叉树
*/
private static TreeNode reConstructBinaryTree(int [] pre,int [] in, int preStart, int preEnd, int inStart, int inEnd) {
if (preStart > preEnd) {
return null;
}
// 根节点的值是前序遍历的第一个值
int rootValue = pre[preStart];
TreeNode treeNode = new TreeNode(rootValue);
// 找到中序遍历序列中的根节点的位置,递归得到左右节点
for (int i = inStart; i <= inEnd; ++i) {
if (in[i] == pre[preStart]) {
treeNode.left = reConstructBinaryTree(pre, in, preStart + 1, preStart + i - inStart, inStart, i - 1);
treeNode.right = reConstructBinaryTree(pre, in, preStart + i - inStart + 1, preEnd, i + 1, inEnd);
break;
}
}
return treeNode;
}
public static void main(String[] args) {
int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
reConstructBinaryTree(pre, in);
}
/**
* 内部类:二叉树结构
*/
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
}
08 二叉树的下一个结点
/**
* 08 二叉树的下一个结点
* 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不 仅包含左右子结点,同时包含指向父结点的指针
* 分三种情况:
* (1)当前节点有右子树,则下一个中序遍历节点是右子树中的最左节点
* (2)当前节点没有右子树,且该节点是其父节点的左节点,则下一个节点是其父节点
* (3)当前节点没有右子树,且该节点是其父节点的右节点,则沿着其父节点向上遍历,直到找到一个 是其父节点的左节点的节点,这个节点的父节点即为所求
*/
/**
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class _08 {
public static TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode == null) {
return null;
}
// 当前节点有右子树
if (pNode.right != null) {
pNode = pNode.right;
while (pNode.left != null) {
pNode = pNode.left;
}
return pNode;
}
// 当前节点没有右子树,且该节点没有父节点,是根节点
if (pNode.next == null) {
return null;
}
// 当前节点没有右子树,且该节点是其父节点的左节点
if (pNode.next.left == pNode) {
return pNode.next;
}
// 当前节点没有右子树,且该节点是其父节点的右节点
if (pNode.next.right == pNode) {
pNode = pNode.next;
while (pNode.next != null) {
if (pNode.next.left != pNode) {
pNode = pNode.next;
} else {
return pNode.next;
}
}
}
return null;
}
/**
* 二叉树结构,包含了指向其父节点的指针
*/
public static class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
}
09 用两个栈实现队列
import java.util.Stack;
/**
* 09 用两个栈实现队列
* 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型
* 栈1的push对应队列的deleteHead操作,栈2的pop操作对应队列的insertTail操作,当栈2为空时, 将栈1的元素依次出栈,进到栈2中,如果栈1也为空,则提示队列为空
*/
public class _09 {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
/**
* 队列的insertTail操作
* @param node 插入队尾的元素
*/
public void push(int node) {
stack1.push(node);
}
/**
* 队列的deleteHead操作
* @return 删除队列头部
*/
public int pop() {
if (stack2.empty()) {
if (stack1.empty()) {
throw new RuntimeException("队列为空");
} else {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
}
return stack2.pop();
}
}
10 斐波那契数列
/**
* 10 斐波那契数列
* 大家都知道斐波那契数列,后一项等于前两项和,现在要求输入一个整数n,请你输出斐波那契数列的 第n项(从0开始,第0项为0,n<=39)。
* 使用两个数将结果前两项缓存即可
*/
public class _10 {
public static int Fibonacci(int n) {
int result = 0;
int temp1 = 0;
int temp2 = 1;
if (n == 1) {
return temp2;
}
for (int i = 1; i < n; i++) {
result = temp1 + temp2;
temp1 = temp2;
temp2 = result;
}
return result;
}
public static void main(String[] args) {
System.out.println("Fibonacci(3) = " + Fibonacci(3));
}
}
剑指offer题解02-10的更多相关文章
- 剑指offer题解(Java版)
剑指offer题解(Java版) 从尾到头打印链表 题目描述 输入一个链表,按从尾到头的顺序返回一个ArrayList. 方法1:用一个栈保存从头到尾访问链表的每个结点的值,然后按出栈顺序将各个值存入 ...
- 剑指offer(leetcode 10.) 正则表达式匹配
这题一年前就做过,当时刚开始刷leetcode,提交了几十次过不去,就放那没管了.今天剑指offer又遇到这题,终于做出来了,用的dp. class Solution { public: bool i ...
- 剑指offer题解
数组中重复的数字 题目描述:在一个长度为n的数组里面的所有数字都在0~n-1的范围内.数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次,请找出数组中任意一个重复的数字.例 ...
- 剑指Offer题解(Python版)
https://blog.csdn.net/tinkle181129/article/details/79326023# 二叉树的镜像 链表中环的入口结点 删除链表中重复的结点 从尾 ...
- 剑指offer第二版-10.斐波那契数列
面试题10:斐波那契数列 题目要求: 求斐波那契数列的第n项的值.f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) n>1 思路:使用循环从下往上计算数列. 考点:考察对递归 ...
- 剑指offer——面试题10:斐波那契数列
个人答案: #include"iostream" #include"stdio.h" #include"string.h" using na ...
- 【剑指Offer】02、替换空格
题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 题解:StringBuffer ...
- 剑指Offer题解索引
数组 数组中重复的数字 二维数组中的查找 构建乘积数组 字符串 替换空格 字符流中第一个不重复的字符 表示数值的字符串 递归和循环 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 链表 从尾到头打印链表 ...
- 剑指offer【02】- 替换空格(Java)
题目:替换空格 考点:字符串 题目描述: 请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. ...
随机推荐
- numpy和TensorFlow的函数
pycharm jupyter notebook 环境配置
- ajax 传递数组类型参数后台接收不到的问题
在做排序功能的时候需要将一个数组的数据传递到后台,(当时怎么没用json,如果用json就没有那么多的事情了),数据提交采用ajax! 先看代码 js: submitbtn: function () ...
- 滚动插件 animatescroll(可以设置要滚动到位置)
1. 引入 <script src="js/animatescroll.js"></script> 2.设置要滚动到的位置 $('目标位置').an ...
- Java版斯诺克开源分享
Java版斯诺克开源分享 这个小程序是我平时无聊写着玩的,在网盘里躺了好久了,今天就把它拿出来跟大家分享一下,下面是游戏截图: 请不要吐槽这个界面,斯诺克的球台是我从qq游戏里面截取的... 下面是源 ...
- ChannelOption用到的socket的标准参数
ChannelOption.SO_BACKLOG, 1024 BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最 ...
- JDK源码分析之concurrent包(二) -- 线程池ThreadPoolExecutor
上一篇我们简单描述了Executor框架的结构,本篇正式开始并发包中部分源码的解读. 我们知道,目前主流的商用虚拟机在线程的实现上可能会有所差别.但不管如何实现,在开启和关闭线程时一定会耗费很多CPU ...
- 巨蟒python全栈开发数据库前端6:事件onclick的两种绑定方式&&onblur和onfocus事件&&window.onload解释&&小米商城讲解
1.回顾上节内容(JavaScript) 一.JavaScript概述 1.ECMAScript和JavaScript的关系 2.ECMAScript的历史 3.JavaScript是一门前后端都可以 ...
- 11.css定义下拉菜单
注意点: 1.设置a标签的width 和 height 的时候,直接设置是没用的,可以以这样两种方式设置 (1). display:block; (2). float:left; 2.设置下拉菜单,最 ...
- The Ultimate Guide To A/B Testing
w http://blog.jobbole.com/25576/?utm_source=blog.jobbole.com&utm_medium=relatedPosts https://www ...
- IO 流中编码和解码问题
编码表 ASCII : American Standard Code for Information Interchange 使用一个字节的 7 位可以表示 ISO8859-1 : 拉丁码表. 欧洲码 ...