1.二维数组中的查找
题目描述
利用二维数组由上到下,由左到右递增的规律,
那么选取右上角a[row][col]与target进行比较,如果等于就直接找到,
当target小于元素a[row][col]时,那么target必定在元素a所在行的左边,
即col--;
当target大于元素a[row][col]时,那么target必定在元素a所在列的下边,
即row++;
public class Solution {
public boolean Find(int target, int [][] array) {int row=0;int col=array[0].length-1;while(row<=array.length-1&&col>=0){if(target==array[row][col]) return true; else if(target>array[row][col]) row++; else col--; } return false; } }
注意:
对于一个二维数组:
int[][] arr = { {2,3,4}, {4,5,6}, {7,8,9} };
int rows = i.length;//行数
int columns = i[0].length;//列数
[[]]这样一个数组代表行数是1,列数时0.
2.替换空格
题目描述
public class Solution {public String replaceSpace(StringBuffer str) {StringBuffer strCopy= new StringBuffer();for(int i=0 ; i<str.length();i++){String c = String.valueOf(str.charAt(i));if(c.equals(" ")){ strCopy.append("%20"); }else { strCopy.append(c); } } return strCopy.toString(); } }
注意:
Java中字符数组、String类、StringBuffer三者的相互转换
3.从尾到头打印链表
题目描述
思路:遇到先进后出的情况,可以采取两种思路:
1.利用堆栈的思想
2.利用递归的思想
下面是采用堆栈的思想:
/** * public class ListNode { * int val; * ListNode next = null; * * ListNode(int val) { * this.val = val; * } * } * */ import java.util.ArrayList; import java.util.Stack; public class Solution {public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {Stack<ListNode> stack = new Stack<ListNode>();while(listNode!=null){stack.push(listNode);listNode = listNode.next; } ArrayList<Integer> list = new ArrayList<Integer>(); while(!stack.isEmpty()){ list.add(stack.pop().val); } return list; } }
下面是采用递归的思想 :
import java.util.ArrayList; public class Solution {ArrayList<Integer> list = new ArrayList<Integer>();public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {if(listNode!=null){this.printListFromTailToHead(listNode.next); list.add(listNode.val); } return list; } }
4.重建二叉树
题目描述
import java.util.*; /*** Definition for binary tree* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/ public class Solution {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(pre[0] == in[i]){ 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; } }
这是形式最为简洁的方法,首先前序的第一个数字肯定是根节点,然后根据这个元素在中序中找到根节点位置i,
那么中序左边0,i是左子树,右边i+1,in.length是右子树。
并且也能在前序中确定左子树是从1,i+1的元素,右子树是i+1,pre.length。(注意这里是左边界包含,右边界不包含)
然后从原数组中分别复制前序和中序的左子树和右子树,递归调用即可。直到pre.length或者in.length(当然这里他俩本来就一样)为0表示递归到叶子节点。
注:Arrays.copyOfRange()方法
startPre>endPre||startIn>endIn为表示已经递归完成
public class Solution {public TreeNode reConstructBinaryTree(int [] pre,int [] in) {TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);return root;}//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {if(startPre>endPre||startIn>endIn) return null; TreeNode root=new TreeNode(pre[startPre]); for(int i=startIn;i<=endIn;i++) if(in[i]==pre[startPre]){ root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1); root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn); break; } return root; } }
5.用两个栈实现队列
题目描述
import java.util.Stack;public class Solution {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.empty()){ while(!stack1.empty()){ stack2.push(stack1.pop()); } } return stack2.pop(); } }
6.旋转数组的最小数字
题目描述
public int minNumberInRotateArray(int[] array) {if (array.length == 0)return 0;for (int i = 0; i < array.length - 1; i++) {if (array[i] > array[i + 1])return array[i + 1]; } return array[0]; }
3.采用二分法解答这个问题,
import java.util.ArrayList; public class Solution {public int minNumberInRotateArray(int [] array) {int low = 0;int high = array.length-1;while(low<high){int mid = (low + high)/2; if(array[mid]<array[high]){ high=mid; }else if(array[mid]==array[high]){ high = high-1; }else{ low = mid +1; } } return array[low]; } }
7——10 都是斐波拉契数列的变形题
7.斐波拉契数列
题目描述
n<=39
public class Solution {public int Fibonacci(int n) {if(n<2)return n;int fb1 = 0;int fb2 = 1; int fbn = 0; for(int i=2;i<=n;i++){ fbn = fb1+fb2; fb1 = fb2; fb2 = fbn; } return fbn; } }
8.跳台阶
题目描述
| 1, (n=1)
f(n) = | 2, (n=2)
对于本题,前提只有 一次 1阶或者2阶的跳法。
a.如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1);
b.假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2)
c.由a\b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2)
d.然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2
e.可以发现最终得出的是一个斐波那契数列:
思路:
1.用迭代的方法
public int JumpFloor(int target) {if(target == 1 || target == 2)return target;int floorOne = 1;int floorTwo = 2;int floorSum = 0; for(int i=3;i<=target;i++){ floorSum = floorOne +floorTwo; floorOne = floorTwo; floorTwo = floorSum; } return floorSum; }
2.用递归的方法
public int JumpFloor(int target) {if(target == 1 || target == 2){return target;}else{return JumpFloor(target-1)+JumpFloor(target-2);}}
9.变态跳台阶
题目描述
思路:
每个台阶都有跳与不跳两种情况(除了最后一个台阶),最后一个台阶必须跳。所以共用2^(n-1)中情况
解法有两种:一种用移位操作,一个用Math工具
import java.lang.Math; public class Solution {public int JumpFloorII(int target) {//return (int)Math.pow(2,target-1);return 1<< --target;} }
10.矩形的覆盖
题目描述
public class Solution {public int RectCover(int target) {if(target == 1 || target == 2)return target;int floorOne = 1;int floorTwo = 2; int floorSum = 0; for(int i=3;i<=target;i++){ floorSum = floorOne +floorTwo; floorOne = floorTwo; floorTwo = floorSum; } return floorSum; } }
11.二进制中1的个数
题目描述
方法:
1.最简单方法
return Integer.bitCount(n);
2.用1(1自身左移运算,其实后来就不是1了)和n的每位进行位与,来判断1的个数
public int NumberOf1(int n) {int count = 0;int flag1 = 1;while (flag1 != 0){if((n & flag1 ) != 0)count++; flag1 = flag1<<1; } return count; } }
3.如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
public class Solution {public int NumberOf1(int n) {int count = 0;while(n!= 0){count++;n = n & (n - 1); } return count; } }
12.数值的整数次方
题目描述
public class Solution {public double Power(double base, int exponent) {if(base == 0 && exponent < 0){throw new RuntimeException("分母不能为0");}else if(exponent==0){return 1; } double absResult = 0; if(exponent<0){ absResult = absExponent(base,-exponent); absResult = 1/absResult; }else{ absResult = absExponent(base,exponent); } return absResult; } public double absExponent(double base,double exponent){ double result = base; for(int i=1;i<exponent;i++){ result = base*result; } return result; } }
13.调整数组使奇数位于偶数前面
题目描述
思路:
时间复杂度为O(n),空间复杂度为O(n)的算法,用空间换时间
public class Solution {public void reOrderArray(int [] array) {int[] tempArray = new int[array.length];int j =0;for (int i = 0; i<array.length;i++){if((array[i]&1) == 1){ tempArray[j] = array[i]; j++; } } for (int i = 0; i<array.length;i++){ if((array[i]&1) != 1){ tempArray[j] = array[i]; j++; } } for(int i=0;i<array.length;i++){ array[i] = tempArray[i]; } } }
14.链表中第k个节点
题目描述
public class Solution {public ListNode FindKthToTail(ListNode head,int k) {//头结点为空节点或者输入的k为0if (head == null || k == 0){return null;}ListNode listA = head;ListNode listB = head; for (int i=0; i<k-1;i++){ if(listA.next != null) listA = listA.next; //链表的长度小于k else return null; } //遍历链表一次找到第k个节点 while(listA.next != null){ listA = listA.next; listB = listB.next; } return listB; } }
2.遇到这种倒置行为一定要想到堆栈,使用Stack,将结点压入栈中,再取出第k个就好
if(head == null || k ==0 ){return null;}//可以先把链表反转,然后找出第k个Stack<ListNode> stack = new Stack<ListNode>();int count = 0;while(head != null){stack.push(head);head = head.next; count++; } if(count < k){ return null; } ListNode knode = null; for(int i = 0; i < k; i++){ knode = stack.pop(); } return knode;
15.反转链表
题目描述
public class Solution { public ListNode ReverseList(ListNode head) {if(head==null)return null;//head为当前节点,如果当前节点为空的话,那就什么也不做,直接返回null;ListNode pre = null;ListNode next = null;//当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点//需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2//即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了//所以需要用到pre和next两个节点//1->2->3->4->5//1<-2<-3 4->5、while(head!=null){//做循环,如果当前节点不为空的话,始终执行此循环,此循环的目的就是让当前节点从指向next到指向pre//如此就可以做到反转链表的效果//先用next保存head的下一个节点的信息,保证单链表不会因为失去head节点的原next节点而就此断裂next = head.next;//保存完next,就可以让head从指向next变成指向pre了,代码如下head.next = pre;//head指向pre后,就继续依次反转下一个节点//让pre,head,next依次向后移动一个节点,继续下一次的指针反转pre = head;head = next;}//如果head为null的时候,pre就为最后一个节点了,但是链表已经反转完毕,pre就是反转后链表的第一个节点//直接输出pre就是我们想要得到的反转后的链表return pre;} }
16.合并两个排序的链表
题目描述
public class Solution {public ListNode Merge(ListNode list1,ListNode list2) {if(list1 == null)return list2;else if(list2 == null)return list1;ListNode mergedHead = null;if(list1.val< list2.val){mergedHead = list1;mergedHead.next = Merge(list1.next,list2);}else{mergedHead = list2;mergedHead.next = Merge(list1,list2.next);}return mergedHead;} }
迭代:
public ListNode Merge(ListNode list1, ListNode list2) {ListNode head = new ListNode(-1);ListNode cur = head;while (list1 != null && list2 != null) {if (list1.val <= list2.val) {cur.next = list1;list1 = list1.next;} else {cur.next = list2;list2 = list2.next;}cur = cur.next;}if (list1 != null)cur.next = list1;if (list2 != null)cur.next = list2;return head.next; }
17.树的子结构
题目描述
1.递归思想,如果根节点相同则递归调用DoesTree1HaveTree2(),
如果根节点不相同,则判断tree1的左子树和tree2是否相同,
再判断右子树和tree2是否相同
Tree2为空,则说明第二棵树遍历完了,即匹配成功;
如果tree1为空&&tree2不为空说明不匹配;如果两个根节点相同则继续遍历判断
public class Solution {public boolean HasSubtree(TreeNode root1,TreeNode root2) {if(root1 ==null || root2 == null)return false;return DoTreeHavaTree2(root1,root2) || HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);}public boolean DoTreeHavaTree2(TreeNode root1,TreeNode root2){if(root2 == null)return true;if(root1 == null)return false;if(root1.val == root2.val)return DoTreeHavaTree2(root1.left,root2.left) && DoTreeHavaTree2(root1.right,root2.right);elsereturn false;} }
18.二叉树的镜像
题目描述
思路:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子节点,
当交换完所有的非叶子结点的左右子结点之后,就得到了树的镜像.
import java.util.Stack; public class Solution {public void Mirror(TreeNode root) {if(root ==null || root.left == null && root.right ==null)return;Stack<TreeNode> tStack = new Stack<TreeNode>(); tStack.add(root);while(tStack.size() != 0){TreeNode p = tStack.pop();if(p.left!=null || p.right!=null){TreeNode temp = p.left;p.left = p.right;p.right = temp;if(p.left != null)tStack.push(p.left);if(p.right != null)tStack.push(p.right);}}} }
19.顺时针打印矩阵
题目描述
import java.util.ArrayList; public class Solution { public ArrayList<Integer> printMatrix(int [][] matrix) {int row = matrix.length;int col = matrix[0].length;ArrayList<Integer> list = new ArrayList<Integer>();if(row == 0 || col ==0) return list;// 定义四个关键变量,表示左上和右下的打印范围int left = 0;int top = 0;int right = col - 1;int bottom = row - 1;while (left <= right && top <= bottom){// left to rightfor(int i = left; i <= right; ++i) list.add(matrix[top][i]);// top to bottomfor (int i = top + 1; i <= bottom; ++i)list.add(matrix[i][right]);// right to left 特别注意这里和后面两个for循环的判断条件,防止单行或者单列出现重复扫描技术的情况//如果top != bottom说明从右到左的扫描不会和之前从左到右重复if (top != bottom)for (int i = right - 1; i >= left; --i)list.add(matrix[bottom][i]);// bottom to topif (left != right) for (int i = bottom - 1; i >= top+1; --i)list.add(matrix[i][left]);left++;top++;right--;bottom--;}return list; } }
20.包含min函数的栈
题目描述
用一个栈data保存数据,用另外一个栈min保存依次入栈最小的数
比如,data中依次入栈,
5
,
4
,
3
,
8
,
10
,
11
,
12
,
1
则min依次入栈,
5
,
4
,
3
,no,no, no, no,
1
no代表此次不入栈
每次入栈的时候,如果入栈的元素比min中的栈顶元素小或等于则入栈,否则不入栈。
import java.util.Stack;public class Solution {Stack<Integer> stack = new Stack<Integer>();Stack<Integer> minstack = new Stack<Integer>();public void push(int node) {stack.push(node);if(minstack.empty() || node < minstack.peek())minstack.push(node);}public void pop() {if(stack.peek() == minstack.peek())minstack.pop();stack.pop();}public int top() {return stack.peek();}public int min() {return minstack.peek();} }
21.栈的压入、弹出序列
题目描述
思路:借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
….
import java.util.ArrayList; import java.util.Stack; public class Solution {public boolean IsPopOrder(int [] pushA,int [] popA) {if(pushA.length == 0 || popA.length == 0)return false;int popIndex = 0;Stack <Integer> s = new Stack<Integer>();for(int i=0;i<pushA.length;i++){s.push(pushA[i]);while(!s.empty() && popA[popIndex] == s.peek()){s.pop();popIndex++;}}return s.empty();} }
22.从上向下打印二叉树
题目描述
public class Solution {public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {LinkedList<TreeNode> q = new LinkedList<TreeNode>();ArrayList <Integer> list = new ArrayList<Integer>();if(root == null)return list;q.offer(root);while(!q.isEmpty()){TreeNode p = q.poll();list.add(p.val);if(p.left != null)q.offer(p.left);if(p.right != null)q.offer(p.right);}return list;} }
递归解法:
import java.util.ArrayList; public class Solution {ArrayList<Integer> list=new ArrayList<Integer>();public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {if(root!=null)list.add(root.val);print(root);return list;}public void print(TreeNode root){if(root!=null){if(root.left!=null)list.add(root.left.val);if(root.right!=null)list.add(root.right.val);print(root.left);print(root.right);}} }
23.二叉搜索树的后序遍历
题目描述
import java.util.*; public class Solution {public static boolean VerifySquenceOfBST(int [] sequence) {int length = sequence.length;if(sequence == null || sequence.length == 0)return false;
//在二叉搜索树中左子树节点的值小于根节点的值,找到最后一个左子树节点int i = 0;for(;i<sequence.length-1;i++){if(sequence[i]>sequence[length-1])break;}//在二叉搜索树中右子树节点的值大于根节点的值int j = i;for(;j<sequence.length-1;j++){if(sequence[j]<sequence[length-1])return false;}boolean left = true;if(i>0)left = VerifySquenceOfBST(Arrays.copyOfRange(sequence, 0, i));boolean right = true;if(i<length-1)right = VerifySquenceOfBST(Arrays.copyOfRange(sequence,i,length-1));return left && right;} }
24.二叉树中和为某一值的路径
题目描述
public class Solution {private ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();private ArrayList<Integer> list = new ArrayList<Integer>();public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {if(root == null) return listAll;list.add(root.val);target -= root.val;if(target == 0 && root.left == null && root.right == null)listAll.add(new ArrayList<Integer>(list));FindPath(root.left, target);FindPath(root.right, target);//回退的时候删去当前节点list.remove(list.size()-1);return listAll;} }
25.复杂链表的复制
题目描述
/*1、复制每个节点,如:复制节点A得到A1,将A1插入节点A后面2、遍历链表,A1->random = A->random->next;3、将链表拆分成原链表和复制后的链表*/ public class Solution {public RandomListNode Clone(RandomListNode pHead){if(pHead == null)return null;RandomListNode node = pHead;while(node != null){RandomListNode cloneNode = new RandomListNode(node.label);cloneNode.next = node.next;node.next = cloneNode;node = cloneNode.next;}node = pHead;while(node != null){if(node.random != null)node.next.random = node.random.next;node = node.next.next;}RandomListNode head = pHead.next;RandomListNode cloneNode = head;node = pHead;while(node != null){node.next = node.next.next;if(node.next != null)cloneNode.next = cloneNode.next.next;node = node.next;cloneNode = cloneNode.next;}return head;} }