剑指offer 1-5
1二维数组的查找:
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
一、暴力法
时间复杂度:
空间复杂度:O(1)
二、从左下找
利用该二维数组的性质:
- 每一行都按照从左到右递增的顺序排序,
- 每一列都按照从上到下递增的顺序排序
改变个说法,即对于左下角的值 m,m 是该行最小的数,是该列最大的数
每次将 m 和目标值 target 比较:
- 当 m < target,由于 m 已经是该行最大的元素,想要更大只有从列考虑,取值右移一位
- 当 m > target,由于 m 已经是该列最小的元素,想要更小只有从行考虑,取值上移一位
- 当 m = target,找到该值,返回 true
用某行最小或某列最大与 target 比较,每次可剔除一整行或一整列
时间复杂度:
空间复杂度:O(1)
//二维数组的查找
public class theSeekOfTwodDmensionalArray {
public static void main(String[] args) {
theSeekOfTwodDmensionalArray seek = new theSeekOfTwodDmensionalArray();
int target = 12;
int[][] array = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
boolean flag = seek.Find(target, array);
System.out.println(flag);
}
public boolean Find(int target, int [][] array) {
boolean flag = false;
int row = array.length-1;
int col = 0;
while(row >= 0 && col <=array[0].length-1) {
if(array[row][col] < target) {
col++;
}else if(array[row][col] > target) {
row--;
}else {
return true;
}
}
return false;
}
}
2替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
一、在当前字符串上进行替换。
- 先计算替换后的字符串需要多大的空间,并对原字符串空间进行扩容;
- 从后往前替换字符串的话,每个字符串只需要移动一次;
- 如果从前往后,每个字符串需要多次移动,效率较低
- 时间复杂度:O(length) 只遍历了一遍字符串
空间复杂度:O(1) 没有开辟空间
public class Solution {
public static String replaceSpace(StringBuffer s) {
int count=0;
int length=s.length();
//统计空格数量
for(int i=0;i<length;i++){
if(s.charAt(i)==' '){
count++;
}
}
//新长度
int newLength=length+count*2-1;
s.setLength(newLength+1);
//从后往前
for(int i=length-1;i>=0;i--){
if(s.charAt(i)==' '){
s.setCharAt(newLength--,'0');
s.setCharAt(newLength--,'2');
s.setCharAt(newLength--,'%');
}else{
s.setCharAt(newLength--,s.charAt(i));
}
}
return s.toString();
}
}
二、调用自带函数
三、用新的數組存
当遇到 " ",就追加 "%20",否则遇到什么追加什么
public class replaceSpaceTest {
public static void main(String[] args) {
replaceSpaceTest replacespace = new replaceSpaceTest();
String str = "dog is animal";
StringBuffer stringbuffer = new StringBuffer(str);
String s = replacespace.replaceSpace(stringbuffer);
System.out.println(s);
}
//调用库函数
public String replaceSpace1(StringBuffer str) {
return str.toString().replace(" ", "%20");
}
//追加
public String replaceSpace(StringBuffer str) {
StringBuilder stringbuilder = new StringBuilder();
for(int i =0; i < str.length();i++) {
if(str.charAt(i) == ' ') {
stringbuilder.append("%20");
}else {
stringbuilder.append(str.charAt(i));
}
}
return stringbuilder.toString();
}
}
3从尾到头打印链表
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
使用ArrayList的add(index,value)
时间复杂度:
空间复杂度:
package list;
import java.util.ArrayList;
import java.util.Scanner;
public class printListFromTailToHeadTest {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
ListNode l = new ListNode(-1);
ListNode l1 = l;
while (!s.hasNext("!")) {
l1.next = new ListNode(s.nextInt());
l1 = l1.next;
}
ArrayList<Integer> res = printListFromTailToHead(l.next);
System.out.println(res.toString());
}
public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<>();
while (listNode != null) {
list.add(0, listNode.val);
listNode = listNode.next;
}
return list;
}
}
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
import java.util.ArrayList;
//使用递归实现
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode==null)return list;
print(listNode);
return list;
}
ArrayList<Integer> list=new ArrayList<>();
public void print(ListNode listNode){
if(listNode!=null){
if(listNode.next!=null){
print(listNode.next);
}
}
list.add(listNode.val);
}
}
4重建二叉树
根据中序遍历和前序遍历可以确定二叉树,具体过程为:
- 根据前序序列第一个结点确定根结点
- 根据根结点在中序序列中的位置分割出左右两个子序列
- 对左子树和右子树分别递归使用同样的方法继续分解
例如:
前序序列{1,2,4,7,3,5,6,8} = pre
中序序列{4,7,2,1,5,3,8,6} = in
- 根据当前前序序列的第一个结点确定根结点,为 1
- 找到 1 在中序遍历序列中的位置,为 in[3]
- 切割左右子树,则 in[3] 前面的为左子树, in[3] 后面的为右子树
- 则切割后的左子树前序序列为:{2,4,7},切割后的左子树中序序列为:{4,7,2};切割后的右子树前序序列为:{3,5,6,8},切割后的右子树中序序列为:{5,3,8,6}
- 对子树分别使用同样的方法分解
- 时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)
import java.util.Arrays;
public class reconstructionOfBinaryTree {
public static void main(String[] args) {
reconstructionOfBinaryTree binaryTree = new reconstructionOfBinaryTree();
int[] pre = {1,2,4,7,3,5,6,8};
int[] in = {4,7,2,1,5,3,8,6};
TreeNode root = binaryTree.reConstructBinaryTree(pre,in);
root.preOrder();
}
//递归
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length == 0 || in.length == 0) {
return null;
}
TreeNode node = new TreeNode(pre[0]);
for(int i = 0; i < in.length; i++) {
if(in[i] == pre[0]) {
node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));
node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1, in.length));
break;
}
}
return node;
}
}
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
//验证构建的二叉树 前序遍历
public void preOrder() {
System.out.println(this.val);
if(this.left != null) {
this.left.preOrder();
}
if(this.right != null) {
this.right.preOrder();
}
}
}
5用两个栈模拟队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型
- 当插入时,直接插入 stack1
- 当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,再弹出 stack2 栈顶元素
- push时间复杂度:
pop空间复杂度:O(1)
import java.util.Stack;
public class twoStacksAnalogqueue {
public static void main(String[] args) {
twoStacksAnalogqueue stack = new twoStacksAnalogqueue();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop());
stack.push(4);
System.out.println(stack.pop());
stack.push(8);
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.isEmpty()) {
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
import java.util.ArrayList; public class printListFromTailToHeadTest { public static void main(String[] args) { printListFromTailToHeadTest print = new printListFromTailToHeadTest(); link l = new link(); for(int i = 0;i < 10;i++) { l.add(i); } ArrayList<Integer> res = print.printListFromTailToHead(l.root); System.out.println(res.toString()); } public ArrayList<Integer> printListFromTailToHead(ListNode listNode){ ArrayList<Integer> list = new ArrayList<>(); while(listNode != null) { list.add(0,listNode.val); listNode = listNode.next; } return list; } } //链表添加结点 class link{ public ListNode root; public void add(int val) { ListNode listNode = new ListNode(val); if(this.root == null) { this.root = listNode; }else { this.root.add(listNode); } } } class ListNode{ int val; ListNode next; public ListNode(int val) { this.val = val; } public void add(ListNode listNode) { if(this.next == null) { this.next = listNode; }else { this.next.add(listNode); } } }
进口的java.util.ArrayList;
公共类printListFromTailToHeadTest {
公共静态无效的主要(字串[] args){
printListFromTailToHeadTest打印=新printListFromTailToHeadTest();
链路L =新链路();
对于(中间体I = 0;我<10; i ++在){
l.add(ⅰ);
}
的ArrayList <Integer>的解析度= print.printListFromTailToHead(l.root);
的System.out.println(res.toString());
}
公共的ArrayList <Integer>的printListFromTailToHead(ListNode listNode){
的ArrayList <Integer>的列表=新的ArrayList <>();
而(listNode!= NULL){
list.add(0,listNode.val);
listNode = listNode.next;
}
返回列表;
}
}
//链表添加结点
类链接{
公共ListNode根;
公共无效添加(INT VAL){
ListNode listNode =新ListNode(VAL);
如果(this.root == NULL){
this.root = listNode;
}其他{
this.root.add(listNode);
}
}
}
类ListNode {
INT VAL;
ListNode未来;
公共ListNode(INT VAL){
this.val = VAL;
}
公共无效添加(ListNode listNode){
如果(this.next == NULL){
this.next = listNode;
}其他{
this.next.add(listNode);
}
}
}
公共类printListFromTailToHeadTest {
公共静态无效的主要(字串[] args){
printListFromTailToHeadTest打印=新printListFromTailToHeadTest();
链路L =新链路();
对于(中间体I = 0;我<10; i ++在){
l.add(ⅰ);
}
的ArrayList <Integer>的解析度= print.printListFromTailToHead(l.root);
的System.out.println(res.toString());
}
公共的ArrayList <Integer>的printListFromTailToHead(ListNode listNode){
的ArrayList <Integer>的列表=新的ArrayList <>();
而(listNode!= NULL){
list.add(0,listNode.val);
listNode = listNode.next;
}
返回列表;
}
}
//链表添加结点
类链接{
公共ListNode根;
公共无效添加(INT VAL){
ListNode listNode =新ListNode(VAL);
如果(this.root == NULL){
this.root = listNode;
}其他{
this.root.add(listNode);
}
}
}
类ListNode {
INT VAL;
ListNode未来;
公共ListNode(INT VAL){
this.val = VAL;
}
公共无效添加(ListNode listNode){
如果(this.next == NULL){
this.next = listNode;
}其他{
this.next.add(listNode);
}
}
}