劍指offer第二版總結(jié)——基于牛客網(wǎng)
1. 在一個二維數(shù)組中(每個一維數(shù)組的長度相同)捞稿,每一行都按照從左到右遞增的順序排序又谋,每一列都按照從上到下遞增的順序排序。請完成一個函數(shù)娱局,輸入這樣的一個二維數(shù)組和一個整數(shù)彰亥,判斷數(shù)組中是否含有該整數(shù)。
public class Solution {
public boolean Find(int target, int [][] array) {
int row = array.length;
int col = array[0].length;
// 從數(shù)組的左下角(或者右上角開始判斷)
int i = row-1, j = 0;
while( i>=0 && j< col)
{
if( target == array[i][j]) {
return true;
}
if( target > array[i][j] ){
j++;
}
else {
i--;
}
}
return false;
}
}
注解:解題的關鍵在于找到排好序的規(guī)則衰齐,左下角和右上角的位置數(shù)正好處于一個可以通過大小進行判斷上下走向任斋。
2. 請實現(xiàn)一個函數(shù),將一個字符串中的每個空格替換成“%20”耻涛。例如仁卷,當字符串為We Are Happy.則經(jīng)過替換之后的字符串為We%20Are%20Happy。
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str.length() == 0 ) return "";
// 找出被替換字符的數(shù)目犬第,java可以省略這一步锦积。
int numOfEmpty = 0;
for(int i =0; i<str.length(); i++ ) {
if( str.charAt(i) == ' ') numOfEmpty++;
}
// 若是C++可以根據(jù)numOfEmpty開辟新空間,而java可以直接使用StringBuffer
StringBuffer outStr = new StringBuffer();
for(int i = 0; i<str.length(); i++ ) {
if( str.charAt(i) == ' ') outStr.append("%20");
else outStr.append(str.charAt(i));
}
return outStr.toString();
}
}
3. 輸入一個鏈表歉嗓,按鏈表值從尾到頭的順序返回一個ArrayList丰介。
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*/
import java.util.Stack;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> arrayList= new ArrayList<>();
Stack<Integer> stack = new Stack<>();
if(listNode == null) return arrayList;
// 遍歷鏈表存入stack中
while( listNode.next != null )
{
stack.push(listNode.val);
listNode = listNode.next;
}
stack.push(listNode.val);
// 將stack中的數(shù)據(jù)放入ArrayList中
while( !stack.isEmpty() ) {
arrayList.add(stack.pop());
}
return arrayList;
}
}
4. 輸入某二叉樹的前序遍歷和中序遍歷的結(jié)果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復的數(shù)字哮幢。例如輸入前序遍歷序列{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 Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode rootNode=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return rootNode;
}
private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
if(startPre>endPre||startIn>endIn)return null;
// 新建根節(jié)點
TreeNode rootNode=new TreeNode(pre[startPre]);
for(int i=startIn;i<=endIn;i++){
// 找到中序中的根節(jié)點
if(in[i]==pre[startPre]){
rootNode.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
rootNode.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
}
}
return rootNode;
}
}
5. 用兩個棧來實現(xiàn)一個隊列橙垢,完成隊列的Push和Pop操作垛叨。 隊列中的元素為int類型。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
// 在一個stack中進
public void push(int node) {
stack1.push(node);
}
// 從stack2中出柜某,若stack2為空嗽元,則從stack1中把數(shù)據(jù)輸出到stack2中
public int pop() {
if(stack2.isEmpty())
{
while(!stack1.isEmpty())
{
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
注解:先進后出兩次為先進先出。
6. 把一個數(shù)組最開始的若干個元素搬到數(shù)組的末尾喂击,我們稱之為數(shù)組的旋轉(zhuǎn)剂癌。 輸入一個非減排序的數(shù)組的一個旋轉(zhuǎn),輸出旋轉(zhuǎn)數(shù)組的最小元素翰绊。 例如數(shù)組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉(zhuǎn)佩谷,該數(shù)組的最小值為1。 NOTE:給出的所有元素都大于0监嗜,若數(shù)組大小為0谐檀,請返回0。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0) return 0;
int left = 0;
int right = array.length - 1;
// 折半查找
while(left < right) {
int mid = (left + right) / 2;
// 統(tǒng)一與右邊比
if(array[mid] > array[right]) {
left = mid + 1;
} else if(array[mid] < array[right]){
// 存在向下取整的情況
right = mid;
} else {
// 相等的情況
right--;
}
}
return array[left];
}
}
7. 大家都知道斐波那契數(shù)列裁奇,現(xiàn)在要求輸入一個整數(shù)n稚补,請你輸出斐波那契數(shù)列的第n項(從0開始,第0項為0)框喳。 n<=39
public class Solution {
public int Fibonacci(int n) {
if(n<=0) return 0;
if(n<=2)return 1;
int preNum =1;
int pre2Num =1;
int outNum = 0;
for(int i = 3; i<=n; i++){
outNum = preNum + pre2Num;
pre2Num = preNum;
preNum = outNum;
}
return outNum;
}
}
8. 一只青蛙一次可以跳上1級臺階课幕,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先后次序不同算不同的結(jié)果)五垮。
public class Solution {
public int JumpFloor(int target) {
if(target<=0) return 0;
if(target<=2) return target;
int preNum =2;
int pre2Num =1;
int outNum = 0;
for(int i = 3; i<=target; i++){
outNum = preNum + pre2Num;
pre2Num = preNum;
preNum = outNum;
}
return outNum;
}
}
9. 一只青蛙一次可以跳上1級臺階乍惊,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法放仗。
public class Solution {
public int JumpFloorII(int target) {
if(target<=0) return 0;
return 1<<(--target);
}
}
注解:f(n) = f(n-1)+f(n-2)...f(1)+1; 由于f(1)=1润绎,遞推可得:f(n)=2^(n-1);
10. 我們可以用21的小矩形橫著或者豎著去覆蓋更大的矩形。請問用n個21的小矩形無重疊地覆蓋一個2*n的大矩形诞挨,總共有多少種方法莉撇?
public class Solution {
public int RectCover(int target) {
if(target<=0) return 0;
if(target<=2) return target;
int preNum =2;
int pre2Num =1;
int outNum = 0;
for(int i = 3; i<=target; i++){
outNum = preNum + pre2Num;
pre2Num = preNum;
preNum = outNum;
}
return outNum;
}
}
注解:這題和青蛙跳沒區(qū)別。
11. 輸入一個整數(shù)惶傻,輸出該數(shù)二進制表示中1的個數(shù)棍郎。其中負數(shù)用補碼表示。
public class Solution {
public int NumberOf1(int n) {
int temp = 1;
int count1 = 0;
while(temp!=0)
{
if( (temp&n)!=0 ) count1++;
// 移動1银室,避免出現(xiàn)負數(shù)移動補1的情況
temp = temp <<1;
}
return count1;
}
}
12. 給定一個double類型的浮點數(shù)base和int類型的整數(shù)exponent涂佃。求base的exponent次方励翼。
public class Solution {
public double Power(double base, int exponent) {
if(exponent==0) return 1;
// 由于要考慮正負數(shù),先統(tǒng)一絕對值計算
int absE = Math.abs(exponent);
if(exponent<0) {
return 1/subPower(base,absE);
}
else{
return subPower(base,absE);
}
}
public double subPower(double base, int exponent) {
if( exponent>1 ){
//折半乘辜荠,提高效率
if( exponent%2 != 0) {
return base * subPower(base, exponent/2) * subPower(base, exponent/2);
}
else{
return subPower(base, exponent/2) * subPower(base, exponent/2);
}
}
return base;
}
}
13. 輸入一個整數(shù)數(shù)組汽抚,實現(xiàn)一個函數(shù)來調(diào)整該數(shù)組中數(shù)字的順序,使得所有的奇數(shù)位于數(shù)組的前半部分伯病,所有的偶數(shù)位于數(shù)組的后半部分造烁,并保證奇數(shù)和奇數(shù),偶數(shù)和偶數(shù)之間的相對位置不變午笛。
import java.util.LinkedList;
import java.util.Queue;
public class Solution {
public void reOrderArray(int [] array) {
Queue<Integer> queue1 = new LinkedList<Integer>();
Queue<Integer> queue2 = new LinkedList<Integer>();
for(int i=0;i<array.length;i++){
if(array[i]%2==1){
queue1.add(array[i]);
}
else {
queue2.add(array[i]);
}
}
for(int i=0;i<array.length;i++){
if(!queue1.isEmpty()) {
array[i]=queue1.poll();
}
else {
array[i]=queue2.poll();
}
}
}
}
14. 輸入一個鏈表惭蟋,輸出該鏈表中倒數(shù)第k個結(jié)點。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
// 雙指針實現(xiàn)
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if ( head == null || k <= 0) {
return null;
}
ListNode fastHead = head;
// 先走k-1步
for(int i=1; i< k; i++) {
if(fastHead.next != null) {
fastHead = fastHead.next;
}
else{
return null;
}
}
// 以前走
while(fastHead.next != null){
head = head.next;
fastHead = fastHead.next;
}
return head;
}
}
15. 輸入一個鏈表季研,反轉(zhuǎn)鏈表后,輸出新鏈表的表頭誉察。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if ( head == null ) {
return null;
}
// 需要前一個与涡,當前,后一個持偏,三個節(jié)點處理轉(zhuǎn)向.
ListNode preNode = head;
ListNode nextNode = null;
//處理首節(jié)點
if(head.next != null){
head = head.next;
preNode.next = null;
}
else{
return head;
}
// 遞歸處理
while(head.next != null) {
nextNode = head.next;
head.next = preNode;
preNode = head;
head = nextNode;
}
// 尾節(jié)點處理
head.next = preNode;
return head;
}
}
16. 輸入兩個單調(diào)遞增的鏈表驼卖,輸出兩個鏈表合成后的鏈表,當然我們需要合成后的鏈表滿足單調(diào)不減規(guī)則鸿秆。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 ==null){
return list2;
}
if(list2 ==null){
return list1;
}
ListNode head = new ListNode(0);
ListNode indexNode = head;
while(list1 != null && list2 !=null){
if(list1.val <= list2.val){
indexNode.next = list1;
list1 = list1.next;
}
else{
indexNode.next = list2;
list2 = list2.next;
}
indexNode = indexNode.next;
}
if(list1 == null){
indexNode.next = list2;
}
else{
indexNode.next = list1;
}
return head.next;
}
}
17. 輸入兩棵二叉樹A酌畜,B,判斷B是不是A的子結(jié)構(gòu)卿叽。(ps:我們約定空樹不是任意一個樹的子結(jié)構(gòu))
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1 == null || root2 == null){
return false;
}
if( root1.val == root2.val ){
if(sameHasSubtree( root1.left, root2.left) && sameHasSubtree( root1.right, root2.right)){
return true;
}
}
if( HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2)){
return true;
}
return false;
}
public boolean sameHasSubtree(TreeNode root1,TreeNode root2) {
if(root2 == null){
return true;
}
if(root1 == null){
return false;
}
if( root1.val == root2.val){
if(sameHasSubtree( root1.left, root2.left) && sameHasSubtree( root1.right, root2.right)){
return true;
}
}
return false;
}
}
18. 操作給定的二叉樹桥胞,將其變換為源二叉樹的鏡像。
public class Solution {
public void Mirror(TreeNode root) {
if(root == null){
return ;
}
if(root.left != null ){
Mirror(root.left);
}
if(root.right != null){
Mirror(root.right);
}
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
19. 輸入一個矩陣考婴,按照從外向里以順時針的順序依次打印出每一個數(shù)字贩虾,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數(shù)字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
if(matrix == null){
return null;
}
ArrayList<Integer> outList = new ArrayList<>();
int row = matrix.length;
int col = matrix[0].length;
// 分四個方向討論遍歷沥阱,注意截止條件就好缎罢。
int left = 0,top = 0,bottom = row - 1,right = col - 1;
while(left <= right && top <= bottom){
for(int i = left;i<=right;i++){
outList.add(matrix[top][i]);
}
for(int j = top+1;j<=bottom;j++){
outList.add(matrix[j][right]);
}
if (top != bottom){
for(int t = right-1;t>=left;t--){
outList.add(matrix[bottom][t]);
}
}
if(left != right){
for(int k = bottom-1;k>top;k--){
outList.add(matrix[k][left]);
}
}
top++;left++;right--;bottom--;
}
return outList;
}
}
20. 定義棧的數(shù)據(jù)結(jié)構(gòu),請在該類型中實現(xiàn)一個能夠得到棧中所含最小元素的min函數(shù)(時間復雜度應為O(1))考杉。
import java.util.Stack;
public class Solution {
Stack<Integer> stack = new Stack<>();
Stack<Integer> minStack = new Stack<>();
public void push(int node) {
stack.push(node);
if( minStack.isEmpty() || node < minStack.peek()){
minStack.push(node);
}
else{
minStack.push(minStack.peek()); // 壓自己
}
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return minStack.peek();
}
}
21. 輸入兩個整數(shù)序列策精,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能為該棧的彈出順序崇棠。假設壓入棧的所有數(shù)字均不相等咽袜。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列枕稀,但4,3,5,1,2就不可能是該壓棧序列的彈出序列酬蹋。(注意:這兩個序列的長度是相等的)
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length != popA.length || pushA.length<=0 || popA.length<=0){
return false;
}
Stack<Integer> stack = new Stack<>();
stack.push(pushA[0]);
for (int i = 0,j = 0; i < popA.length; i++) {
while (j < popA.length && stack.peek() != popA[i]) {
stack.push(pushA[j++]);
}
if(stack.peek() != popA[i]){
return false;
}
stack.pop();
}
return true;
}
}
22. 從上往下打印出二叉樹的每個節(jié)點及老,同層節(jié)點從左至右打印。
import java.util.LinkedList;
import java.util.Queue;
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
ArrayList<Integer> list = new ArrayList<>();
while(root != null){
list.add(root.val);
if( root.left != null){
queue.add(root.left);
}
if( root.right != null){
queue.add(root.right);
}
root = queue.poll();
}
return list;
}
}
23. 輸入一個整數(shù)數(shù)組范抓,判斷該數(shù)組是不是某二叉搜索樹的后序遍歷的結(jié)果骄恶。如果是則輸出Yes,否則輸出No。假設輸入的數(shù)組的任意兩個數(shù)字都互不相同匕垫。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence.length == 0) return false;
return IsTreeBST(sequence, 0, sequence.length-1);
}
public boolean IsTreeBST(int [] sequence,int start,int end ){
if(end <= start) return true;
for (int i = start; i < end; i++) {
if(sequence[i] > sequence[end]) break;
}
// 驗證后面的是否都大于根值
for (int j = i; j < end; j++) {
if(sequence[j] < sequence[end]) return false;
}
return IsTreeBST(sequence, start, i-1) && IsTreeBST(sequence, i, end-1);
}
}
24. 輸入一顆二叉樹的根節(jié)點和一個整數(shù)僧鲁,打印出二叉樹中結(jié)點值的和為輸入整數(shù)的所有路徑。路徑定義為從樹的根結(jié)點開始往下一直到葉結(jié)點所經(jīng)過的結(jié)點形成一條路徑象泵。(注意: 在返回值的list中寞秃,數(shù)組長度大的數(shù)組靠前)
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
ArrayList<Integer> a1=new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> arr=new ArrayList<ArrayList<Integer>>();
path( root, target, arr, a1);
return arr;
}
public void path(TreeNode root, int target, ArrayList<ArrayList<Integer>> arr, ArrayList<Integer> a1 ){
if(root==null){
return ;
}
target -= root.val;
a1.add(root.val);
if(root.left!=null){
path( root.left, target, arr, a1);
}
if(root.right!=null){
path( root.right, target, arr, a1);
}
if(root.left==null && root.right==null && target==0){
arr.add(new ArrayList<Integer>(a1));
}
a1.remove(a1.size()-1);
}
}
注解:本題為保證數(shù)組長度大的在前也通過,若需要保證偶惠,只要加一級的排序就好春寿。
25. 輸入一個復雜鏈表(每個節(jié)點中有節(jié)點值,以及兩個指針忽孽,一個指向下一個節(jié)點绑改,另一個特殊指針指向任意一個節(jié)點),返回結(jié)果為復制后復雜鏈表的head兄一。(注意厘线,輸出結(jié)果中請不要返回參數(shù)中的節(jié)點引用,否則判題程序會直接返回空)
public class Solution {
public RandomListNode Clone(RandomListNode pHead){
if(pHead == null){
return null;
}
RandomListNode p=pHead;
RandomListNode t=pHead;
// next 賦值
while(p!=null){
RandomListNode q=new RandomListNode(p.label);
q.next=p.next;
p.next=q;
p=q.next;
}
// random 賦值
while(t!=null){
RandomListNode q=t.next;
if(t.random!=null)
q.random=t.random.next;
t=q.next;
}
// 拆分
RandomListNode s = new RandomListNode(0);
RandomListNode s1 = s;
while (pHead != null) {
RandomListNode q = pHead.next;
pHead.next = q.next;
s.next = q;
s = s.next;
pHead = pHead.next;
}
return s1.next;
}
}
26. 輸入一棵二叉搜索樹出革,將該二叉搜索樹轉(zhuǎn)換成一個排序的雙向鏈表造壮。要求不能創(chuàng)建任何新的結(jié)點,只能調(diào)整樹中結(jié)點指針的指向骂束。
public class Solution {
TreeNode head = null;
TreeNode realHead = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree == null)
return null;
Convert(pRootOfTree.left);
if (realHead == null) {
head = pRootOfTree;
realHead = pRootOfTree;
} else {
head.right = pRootOfTree;
pRootOfTree.left = head;
head = pRootOfTree;
}
Convert(pRootOfTree.right);
return realHead;
}
}
27. 輸入一個字符串,按字典序打印出該字符串中字符的所有排列耳璧。例如輸入字符串a(chǎn)bc,則打印出由字符a,b,c所能排列出來的所有字符串a(chǎn)bc,acb,bac,bca,cab和cba。
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<String> Permutation(String str)
{
ArrayList<String> res=new ArrayList<String>();
if(str.length()==0||str==null)return res;
char[] chars = str.toCharArray();
Permutation(chars, 0, res);
// 字典序排序
Collections.sort(res);
return res;
}
public void Permutation(char[] chars, int begin, ArrayList<String> result) {
if(chars==null || chars.length==0 || begin<0 || begin>chars.length-1) {
return ;
}
if(begin==chars.length-1){
result.add(new String(chars));
}
// 最初自己的排序也是要算上的
for(int i=begin;i<chars.length;i++)
{
if(i==begin||chars[begin]!=chars[i])
{
swap(chars,begin,i);
Permutation( chars, begin+1, result);
swap(chars,begin,i);
}
}
}
public void swap(char[]t,int i,int j)
{
char c=t[i];
t[i]=t[j];
t[j]=c;
}
}
注解:這種都是典型的回溯法(1展箱,n-1)
28. 數(shù)組中有一個數(shù)字出現(xiàn)的次數(shù)超過數(shù)組長度的一半楞抡,請找出這個數(shù)字。例如輸入一個長度為9的數(shù)組{1,2,3,2,2,2,5,4,2}析藕。由于數(shù)字2在數(shù)組中出現(xiàn)了5次召廷,超過數(shù)組長度的一半,因此輸出2账胧。如果不存在則輸出0竞慢。
import java.util.HashMap;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int i = 0; i<array.length; i++){
if(map.containsKey(array[i])){
map.put(array[i], map.get(array[i]) + 1 );
}
else{
map.put(array[i], 1 );
}
}
for (Integer key : map.keySet()) {
if ( map.get(key) > array.length/2){
return key;
}
}
return 0;
}
}
注解:由于不存在的可能性,故劍指offer中的技巧不能用治泥。
29. 輸入n個整數(shù)筹煮,找出其中最小的K個數(shù)。例如輸入4,5,1,6,2,7,3,8這8個數(shù)字居夹,則最小的4個數(shù)字是1,2,3,4,败潦。
import java.util.Collections;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(input.length < 1 || k > input.length) return res;
for(int i =0; i<input.length; i++){
res.add(input[i]);
}
Collections.sort(res);
ArrayList<Integer> out = new ArrayList<Integer>();
for(int i =0; i<k; i++){
out.add(res.get(i));
}
return out;
}
}
注解:這題真扯淡
30. HZ偶爾會拿些專業(yè)問題來忽悠那些非計算機專業(yè)的同學本冲。今天測試組開完會后,他又發(fā)話了:在古老的一維模式識別中,常常需要計算連續(xù)子向量的最大和,當向量全為正數(shù)的時候,問題很好解決。但是,如果向量中包含負數(shù),是否應該包含某個負數(shù),并期望旁邊的正數(shù)會彌補它呢劫扒?例如:{6,-3,-2,7,-15,1,2,2},連續(xù)子向量的最大和為8(從第0個開始,到第3個為止)檬洞。給一個數(shù)組,返回它的最大連續(xù)子序列的和沟饥,你會不會被他忽悠滋碚?(子向量的長度至少是1)
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array == null){
return 0;
}
int[] arr2 = new int[array.length];
arr2[0] = array[0];
for(int i=1; i< array.length; i++){
// 核心思想
if(arr2[i-1] < 0){
arr2[i] = array[i];
}
else{
arr2[i] = arr2[i-1] + array[i];
}
}
int max = arr2[0];
for(int i=1; i< array.length; i++){
if(arr2[i]>max){
max = arr2[i];
}
}
return max;
}
}
31. 求出113的整數(shù)中1出現(xiàn)的次數(shù),并算出1001300的整數(shù)中1出現(xiàn)的次數(shù)贤旷?為此他特別數(shù)了一下1~13中包含1的數(shù)字有1广料、10、11幼驶、12艾杏、13因此共出現(xiàn)6次,但是對于后面問題他就沒轍了。ACMer希望你們幫幫他,并把問題更加普遍化,可以很快的求出任意非負整數(shù)區(qū)間中1出現(xiàn)的次數(shù)(從1 到 n 中1出現(xiàn)的次數(shù))盅藻。
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int base = 1;
int count =0;
int round = n;
int weight = 0购桑;
while(round>0){
weight = round%10;
round = round /10;
// 按位計算1的數(shù)目
count += round * base;
if(weight==1){
count += (n % base) + 1;
}
else if (weight>1) {
count += base;
}
base *= 10;
}
return count;
}
}
32. 輸入一個正整數(shù)數(shù)組,把數(shù)組里所有數(shù)字拼接起來排成一個數(shù)萧求,打印能拼接出的所有數(shù)字中最小的一個其兴。例如輸入數(shù)組{3顶瞒,32夸政,321},則打印出這三個數(shù)字能排成的最小數(shù)字為321323榴徐。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class Solution {
public String PrintMinNumber(int [] numbers) {
if(numbers == null || numbers.length == 0) return "";
int len = numbers.length;
String[] str = new String[len];
StringBuilder sb = new StringBuilder();
// 數(shù)字可能越界守问,轉(zhuǎn)字符串計算
for(int i = 0; i < len; i++){
str[i] = String.valueOf(numbers[i]);
}
Arrays.sort(str,new Comparator<String>(){
@Override
public int compare(String s1, String s2) {
String c1 = s1 + s2;
String c2 = s2 + s1;
return c1.compareTo(c2);
}
});
for(int i = 0; i < len; i++){
sb.append(str[i]);
}
return sb.toString();
}
}
33. 把只包含質(zhì)因子2、3和5的數(shù)稱作丑數(shù)(Ugly Number)坑资。例如6耗帕、8都是丑數(shù),但14不是袱贮,因為它包含質(zhì)因子7仿便。 習慣上我們把1當做是第一個丑數(shù)。求按從小到大的順序的第N個丑數(shù)攒巍。
public class Solution {
public int GetUglyNumber_Solution(int index) {
if( index<=1 ) return index;
int[] list = new int[index];
list[0] = 1;
int temp2=0,temp3=0,temp5=0;
int count = 0;
while( count<index-1 ){
while(list[temp2]*2<=list[count]){
temp2++;
}
while(list[temp3]*3<=list[count]){
temp3++;
}
while(list[temp5]*5<=list[count]){
temp5++;
}
list[++count] = Math.min(Math.min(2*list[temp2], 3*list[temp3]) , 5*list[temp5]);
}
return list[list.length-1];
}
}
注解:空間換時間算法
34. 在一個字符串(0<=字符串長度<=10000嗽仪,全部由字母組成)中找到第一個只出現(xiàn)一次的字符,并返回它的位置, 如果沒有則返回 -1(需要區(qū)分大小寫).
import java.util.LinkedHashMap;
public class Solution {
public static int FirstNotRepeatingChar(String str) {
LinkedHashMap <Character, Integer> map = new LinkedHashMap<Character, Integer>();
for(int i=0;i<str.length();i++){
if(map.containsKey(str.charAt(i))){
map.put(str.charAt(i), map.get(str.charAt(i)) + 1 );
}
else {
map.put(str.charAt(i), 1);
}
}
int i=0;
for(;i<str.length();i++){
char c = str.charAt(i);
if (map.get(c) == 1) {
return i;
}
}
return -1;
}
}
注解:借助hashmap
35. 在數(shù)組中的兩個數(shù)字,如果前面一個數(shù)字大于后面的數(shù)字柒莉,則這兩個數(shù)字組成一個逆序?qū)ξ偶帷]斎胍粋€數(shù)組,求出這個數(shù)組中的逆序?qū)Φ目倲?shù)P。并將P對1000000007取模的結(jié)果輸出兢孝。 即輸出P%1000000007
public class Solution {
public static int InversePairs(int [] array) {
if(array==null||array.length==0){
return 0;
}
int[] copy = new int[array.length];
int count = InversePairsCore( array, copy, 0, array.length-1);//數(shù)值過大求余
return count;
}
private static int InversePairsCore( int[] array, int[] copy, int low, int high)
{
if(low==high){
return 0;
}
int mid = (low+high)>>1;
int leftCount = InversePairsCore( array, copy, low, mid);
int rightCount = InversePairsCore( array, copy, mid+1, high);
int count = 0;
int i=mid;
int j=high;
int locCopy = high;
// 歸并排序窿凤,保證有序
while(i>=low&&j>mid){
if(array[i]>array[j]){
count += j-mid; // 核心計算逆序?qū)Υa
copy[locCopy--] = array[i--];
if(count>=1000000007){
count%=1000000007;
}
}
else{
copy[locCopy--] = array[j--];
}
}
for(;i>=low;i--)
{
copy[locCopy--]=array[i];
}
for(;j>mid;j--)
{
copy[locCopy--]=array[j];
}
// 復制回去仅偎,保證有序
for(int s=low;s<=high;s++)
{
array[s] = copy[s];
}
return (leftCount+rightCount+count)%1000000007;
}
}
注解:這一題肯定可以簡化,懶得改了
36. 輸入兩個鏈表雳殊,找出它們的第一個公共結(jié)點橘沥。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null||pHead2==null){
return null;
}
if(pHead1==pHead2){
return pHead1;
}
int len1=0;
int len2=0;
ListNode curr1=pHead1;
ListNode curr2=pHead2;
while(curr1!=null){
len1++;
curr1=curr1.next;
}
while(curr2!=null){
len2++;
curr2=curr2.next;
}
curr1=pHead1;
curr2=pHead2;
if(len1>len2){
int moreLen=len1-len2;
while(moreLen!=0){
curr1=curr1.next;
moreLen--;
}
}
else{
int moreLen=len2-len1;
while(moreLen!=0){
curr2=curr2.next;
moreLen--;
}
}
while(curr1!=curr2&&curr1!=null){
curr1=curr1.next;
curr2=curr2.next;
}
return curr1;
}
}
37. 統(tǒng)計一個數(shù)字在排序數(shù)組中出現(xiàn)的次數(shù)。
public class Solution {
public int GetNumberOfK(int [] array , int k) {
if(array.length<1) return 0;
int begin =0;
int end = array.length-1;
return GetNumberOfK(array , k, begin, end);
}
public int GetNumberOfK(int[] array,int k, int begin, int end){
if(begin>end)
return 0;
int mid=(end-begin)/2+begin;
if(k>array[mid])
return GetNumberOfK(array,k,mid+1,end);
else if(k<array[mid])
return GetNumberOfK(array,k,begin,mid-1);
else {
return 1+GetNumberOfK(array,k,begin,mid-1)+GetNumberOfK(array,k,mid+1,end);
}
}
}
注解:折半查找提高效率
38. 輸入一棵二叉樹相种,求該樹的深度威恼。從根結(jié)點到葉結(jié)點依次經(jīng)過的結(jié)點(含根、葉結(jié)點)形成樹的一條路徑寝并,最長路徑的長度為樹的深度箫措。
public class Solution {
public int TreeDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(TreeDepth(root.left), TreeDepth(root.right)) + 1;
}
}
39. 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹衬潦。
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if (root == null) {
return true;
}
int left = getTreeDepth(root.left);
int right = getTreeDepth(root.right);
int diff = Math.abs(left - right);
if (diff > 1)
return false;
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
public int getTreeDepth(TreeNode root) {
if (root == null)
return 0;
else
return Math.max(getTreeDepth(root.left), getTreeDepth(root.right)) + 1;
}
}
40. 一個整型數(shù)組里除了兩個數(shù)字之外斤蔓,其他的數(shù)字都出現(xiàn)了偶數(shù)次。請寫程序找出這兩個只出現(xiàn)一次的數(shù)字镀岛。
//num1,num2分別為長度為1的數(shù)組弦牡。傳出參數(shù)
//將num1[0],num2[0]設置為返回結(jié)果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if (array == null) return ;
int binaryVal = array[0];
for(int i=1; i< array.length; i++){
binaryVal ^= array[i];
}
// 找到第一個bit不為1的數(shù)
int binary1 = 1;
while((binary1&binaryVal)==0){
binary1 = binary1<<1;
}
boolean flag1 = true;
boolean flag2 = true;
for(int i=0; i< array.length; i++){
if( (binary1 & array[i]) !=0 && flag1){
num1[0] = array[i];
flag1 = false;
}
else if( (binary1 & array[i]) !=0){
num1[0] = num1[0] ^array[i];
}
else if(flag2){
num2[0] = array[i];
flag2 = false;
}
else{
num2[0] = num2[0] ^array[i];
}
}
}
}
41. 小明很喜歡數(shù)學,有一天他在做數(shù)學作業(yè)時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他并不滿足于此,他在想究竟有多少種連續(xù)的正數(shù)序列的和為100(至少包括兩個數(shù))漂羊。沒多久,他就得到另一組連續(xù)正數(shù)和為100的序列:18,19,20,21,22〖菝蹋現(xiàn)在把問題交給你,你能不能也很快的找出所有和為S的連續(xù)正數(shù)序列? Good Luck!
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer> > list = new ArrayList<ArrayList<Integer> > ();
if(sum<=1)return list;
// 這里是一個優(yōu)化,前提單個數(shù)為100不行
for(int i=1;i<=sum/2;i++){
ArrayList<Integer> List2=new ArrayList<Integer>();
int count=0;
for(int j=i;j<sum;j++){
count+=j;
List2.add(j);
if(count>sum)
break;
else if(count==sum){
list.add(List2);
break;
}
}
}
return list;
}
}
42. 輸入一個遞增排序的數(shù)組和一個數(shù)字S走越,在數(shù)組中查找兩個數(shù)椭豫,使得他們的和正好是S,如果有多對數(shù)字的和等于S旨指,輸出兩個數(shù)的乘積最小的赏酥。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> list = new ArrayList<>();
if(array.length<2) return list;
int begin = 0;
int end = array.length - 1;
while(begin<end){
if( (array[begin] + array[end])< sum){
begin++;
}
else if( (array[begin] + array[end])> sum){
end--;
}
else{
list.add(array[begin]);
list.add(array[end]);
break;
}
}
return list;
}
}
43. 匯編語言中有一種移位指令叫做循環(huán)左移(ROL),現(xiàn)在有個簡單的任務谆构,就是用字符串模擬這個指令的運算結(jié)果裸扶。對于一個給定的字符序列S,請你把其循環(huán)左移K位后的序列輸出搬素。例如瑟匆,字符序列S=”abcXYZdef”,要求輸出循環(huán)左移3位后的結(jié)果蒂教,即“XYZdefabc”。是不是很簡單?OK论悴,搞定它嗜闻!
public class Solution {
public String LeftRotateString(String str,int n) {
if(str.length()<0 || n<0 || n>str.length()) return str;
char[] chars = str.toCharArray();
for(int i = 0; i<chars.length/2; i++){
char temp = chars[i];
chars[i] = chars[chars.length-1-i];
chars[chars.length-1-i] = temp;
}
for(int i = 0; i<(chars.length-n)/2; i++){
char temp = chars[i];
chars[i] = chars[chars.length-n-1-i];
chars[chars.length-n-1-i] = temp;
}
for(int i = chars.length-n; i<(chars.length-n/2); i++){
char temp = chars[i];
chars[i] = chars[chars.length-1-i + chars.length-n];
chars[chars.length-1-i + chars.length-n] = temp;
}
return new String(chars);
}
}
注解:不借助輔助空間的算法病袄,需要兩次翻轉(zhuǎn)纠亚。為了避免混亂,也可以使用前后兩指針交換的算法皂吮。
44. 沤渖担客最近來了一個新員工Fish税手,每天早晨總是會拿著一本英文雜志,寫些句子在本子上需纳。同事Cat對Fish寫的內(nèi)容頗感興趣芦倒,有一天他向Fish借來翻看,但卻讀不懂它的意思不翩。例如兵扬,“student. a am I”。后來才意識到口蝠,這家伙原來把句子單詞的順序翻轉(zhuǎn)了器钟,正確的句子應該是“I am a student.”。Cat對一一的翻轉(zhuǎn)這些單詞順序可不在行妙蔗,你能幫助他么傲霸?
public class Solution {
public String ReverseSentence(String str) {
if(str.length()<1 ) return str;
char[] chars = str.toCharArray();
// 先翻轉(zhuǎn)
for(int i = 0; i<chars.length/2; i++){
char temp = chars[i];
chars[i] = chars[chars.length-1-i];
chars[chars.length-1-i] = temp;
}
int end;
int begin = 0;
for(int i = 0; i<=chars.length-1; i++){
if( chars[i]== ' ' || i==chars.length-1){
end = i - 1;
if(i==chars.length-1){
end++;
}
while(begin<end){
char temp = chars[begin];
chars[begin] = chars[end];
chars[end] = temp;
begin++;
end--;
}
begin = i + 1;
}
}
return new String(chars);
}
}
注解:上一題的一般化
45. LL今天心情特別好,因為他去買了一副撲克牌,發(fā)現(xiàn)里面居然有2個大王,2個小王(一副牌原本是54張_)...他隨機從中抽出了5張牌,想測測自己的手氣,看看能不能抽到順子,如果抽到的話,他決定去買體育彩票,嘿嘿!眉反!“紅心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是順子.....LL不高興了,他想了想,決定大\小 王可以看成任何數(shù)字,并且A看作1,J為11,Q為12,K為13昙啄。上面的5張牌就可以變成“1,2,3,4,5”(大小王分別看作2和4),“So Lucky!”。LL決定去買體育彩票啦寸五。 現(xiàn)在,要求你使用這幅牌模擬上面的過程,然后告訴我們LL的運氣如何梳凛, 如果牌能組成順子就輸出true,否則就輸出false梳杏。為了方便起見,你可以認為大小王是0韧拒。
import java.util.Arrays;
public class Solution {
public boolean isContinuous(int [] numbers) {
if(numbers.length <1)
return false;
Arrays.sort(numbers); //先排序
int zero = 0, i = 0;
for(; i < numbers.length && numbers[i] == 0; i++){
zero ++; //統(tǒng)計0的個數(shù)
}
for(i = zero; i < numbers.length - 1; i++){
if(numbers[i] == numbers[i+1]) //有對子,則返回false
return false;
}
if( (numbers[numbers.length -1] - numbers[zero]+1) <=5 )
return true;
else
return false;
}
}
46. 每年六一兒童節(jié),琶啬客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此叭莫。HF作為诺讣客的資深元老,自然也準備了一些小游戲烁试。其中,有個游戲是這樣的:首先,讓小朋友們圍成一個大圈。然后,他隨機指定一個數(shù)m,讓編號為0的小朋那個小朋友友開始報數(shù)拢肆。每次喊到m-1的要出列唱首歌,然后可以在禮品箱中任意的挑選禮物,并且不再回到圈中,從他的下一個小朋友開始,繼續(xù)0...m-1報數(shù)....這樣下去....直到剩下最后一個小朋友,可以不用表演,并且拿到偶跸欤客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試著想下,哪個小朋友會得到這份禮品呢郭怪?(注:小朋友的編號是從0到n-1)
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if(n==0||m==0)return -1;
int s=0;
for(int i=2;i<=n;i++)
{
s=(s+m)%i;
}
return s ;
}
}
注解:每一次都看成一個新的排序f[i-1]支示,但是下標是從k=m%n開始的。所以上一次的結(jié)果f[i]等于(f[i-1]+k)%n鄙才。于是有:
遞推公式:f[i]=(f[i-1]+k)%n => f[1]=0颂鸿,f[i]=(f[i-1]+m)%i;
47. 求1+2+3+...+n,要求不能使用乘除法攒庵、for嘴纺、while败晴、if、else栽渴、switch尖坤、case等關鍵字及條件判斷語句(A?B:C)。
public class Solution {
public int Sum_Solution(int n) {
int sum = n;
boolean flag = (n>0)&&((sum +=Sum_Solution(n-1))>0);
return sum;
}
}
注解:利用了邏輯&&的截斷功能闲擦。
48. 寫一個函數(shù)慢味,求兩個整數(shù)之和,要求在函數(shù)體內(nèi)不得使用+墅冷、-纯路、*、/四則運算符號寞忿。
public class Solution {
public int Add(int num1, int num2) {
int num3;
int num4;
do {
num3 = num1 ^ num2;
num4 = (num1 & num2) << 1;
num1 = num3;
num2 = num4;
} while (num4 != 0);
return num1;
}
}
注解:通過位運算
49. 將一個字符串轉(zhuǎn)換成一個整數(shù)(實現(xiàn)Integer.valueOf(string)的功能感昼,但是string不符合數(shù)字要求時返回0),要求不能使用字符串轉(zhuǎn)換整數(shù)的庫函數(shù)罐脊。 數(shù)值為0或者字符串不是一個合法的數(shù)值則返回0定嗓。
public class Solution {
public int StrToInt(String str)
{
if ( str.length() < 1)
return 0;
char[] a = str.toCharArray();
boolean fuhao = true;
int begin = 0;
if (a[0] == '-'){
fuhao = false;
begin = 1;
}
else if(a[0] == '+'){
begin = 1;
}
int sum = 0;
for (int i = begin; i < a.length; i++){
if (a[i] < 48 || a[i] > 57)
return 0;
sum = sum * 10 + a[i] - 48;
}
return fuhao ? sum : sum * -1;
}
}
注解:主要符號的判斷。字符0的ASCII碼是48
50. 在一個長度為n的數(shù)組里的所有數(shù)字都在0到n-1的范圍內(nèi)萍桌。 數(shù)組中某些數(shù)字是重復的宵溅,但不知道有幾個數(shù)字是重復的。也不知道每個數(shù)字重復幾次上炎。請找出數(shù)組中任意一個重復的數(shù)字恃逻。 例如,如果輸入長度為7的數(shù)組{2,3,1,0,2,5,3}藕施,那么對應的輸出是第一個重復的數(shù)字2寇损。
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(length <1 ) return false;
for(int i=0;i<length;i++){
while(numbers[i]!=i){
if(numbers[i]==numbers[numbers[i]]){
duplication[0]=numbers[i];
return true;
}
int temp=numbers[i];
numbers[i]=numbers[temp];
numbers[temp]=temp;
}
}
return false;
}
注解:利用數(shù)組值與下標的關系
51. 給定一個數(shù)組A[0,1,...,n-1],請構(gòu)建一個數(shù)組B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。不能使用除法裳食。
import java.util.ArrayList;
public class Solution {
public int[] multiply(int[] A) {
if(A.length<1) return A;
int[] B = new int[A.length];
B[0] = 1;
for(int i=1; i< A.length; i++){
B[i] = B[i-1] * A[i-1];
}
int temp = 1;
for(int i=A.length-2; i>=0; i--){
temp *= A[i+1];
B[i] = B[i] * temp;
}
return B;
}
}
注解:利用前后兩次乘矛市,逃離中間乘。
52. 請實現(xiàn)一個函數(shù)用來匹配包括'.'和''的正則表達式诲祸。模式中的字符'.'表示任意一個字符浊吏,而''表示它前面的字符可以出現(xiàn)任意次(包含0次)。 在本題中救氯,匹配是指字符串的所有字符匹配整個模式找田。例如,字符串"aaa"與模式"a.a"和"abaca"匹配着憨,但是與"aa.a"和"ab*a"均不匹配
public class Solution {
public boolean match(char[] str, char[] pattern) {
return matchTwo(str, 0, str.length, pattern, 0, pattern.length);
}
private boolean matchTwo(char[] str, int i, int length1, char[] pattern, int j, int length2) {
if (i == length1 && j == length2) {
return true;
}
if (i == length1 && j != length2) {
while (j != length2) {
if (pattern[j] != '*' && (j + 1 >= length2 || pattern[j + 1] != '*')) {
return false;
}
j++;
}
return true;
}
if (i != length1 && j == length2) {
return false;
}
if (j + 1 == length2) {
if (str[i] == pattern[j] || pattern[j] == '.')
return matchTwo(str, i + 1, length1, pattern, j + 1, length2);
else {
return false;
}
}
if ((str[i] == pattern[j] || pattern[j] == '.') && pattern[j + 1] != '*')
return matchTwo(str, i + 1, length1, pattern, j + 1, length2);
if ((str[i] == pattern[j] || pattern[j] == '.') && pattern[j + 1] == '*')
return matchTwo(str, i, length1, pattern, j + 2, length2)
|| matchTwo(str, i + 1, length1, pattern, j, length2);
if (pattern[j + 1] == '*')
return matchTwo(str, i, length1, pattern, j + 2, length2);
return false;
}
}
注解:不是我說墩衙,讓你寫一個這種函數(shù)還真不好寫!!F岣摹植袍!
53. 請實現(xiàn)一個函數(shù)用來判斷字符串是否表示數(shù)值(包括整數(shù)和小數(shù))。例如籽懦,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數(shù)值于个。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
public class Solution {
public boolean isNumeric(char[] str) {
String s=String.valueOf(str);
return s.matches("[+-]?[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]+)?");
}
}
54. 請實現(xiàn)一個函數(shù)用來找出字符流中第一個只出現(xiàn)一次的字符暮顺。例如厅篓,當從字符流中只讀出前兩個字符"go"時,第一個只出現(xiàn)一次的字符是"g"捶码。當從該字符流中讀出前六個字符“google"時羽氮,第一個只出現(xiàn)一次的字符是"l"。如果當前字符流沒有存在出現(xiàn)一次的字符惫恼,返回#字符档押。
import java.util.HashMap;
import java.util.ArrayList;
public class Solution {
HashMap<Character, Integer> map=new HashMap<>();
ArrayList<Character> list=new ArrayList<Character>();
public void Insert(char ch)
{
if(map.containsKey(ch)){
map.put(ch,map.get(ch)+1);
}else{
map.put(ch,1);
}
list.add(ch);
}
public char FirstAppearingOnce()
{
char c='#';
for(char key : list){
if(map.get(key)==1){
c=key;
break;
}
}
return c;
}
}
55. 給一個鏈表,若其中包含環(huán)祈纯,請找出該鏈表的環(huán)的入口結(jié)點令宿,否則,輸出null腕窥。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead){
if (pHead == null || pHead.next == null || pHead.next.next == null)
return null;
ListNode slow = pHead.next;
ListNode quick = pHead.next.next;
// 1 找到是否有環(huán)粒没,兩個指針
while (slow != quick) {
if (slow.next != null && quick.next.next != null) {
slow = slow.next;
quick = quick.next.next;
} else{
return null;
}
}
// 2 確定環(huán)的大小k 但是其大小正好是 slow走的距離。 // 3 先走k步簇爆,相遇點為入口癞松。
quick = pHead;
while (quick != slow) {
quick = quick.next;
slow = slow.next;
}
return slow;
}
}
56. 在一個排序的鏈表中,存在重復的結(jié)點入蛆,請刪除該鏈表中重復的結(jié)點响蓉,重復的結(jié)點不保留,返回鏈表頭指針哨毁。 例如枫甲,鏈表1->2->3->3->4->4->5 處理后為 1->2->5
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
ListNode result;
ListNode temp = pHead;
ListNode index = new ListNode(1);
index.next = pHead;
result = index;
while (temp != null) {
if (temp.next != null && temp.next.val == temp.val) {
while (temp.next != null && temp.next.val == temp.val) {
temp = temp.next;
}
temp = temp.next;
index.next = temp;
} else {
index = index.next;
temp = temp.next;
}
}
return result.next;
}
}
57. 給定一個二叉樹和其中的一個結(jié)點,請找出中序遍歷順序的下一個結(jié)點并且返回挑庶。注意言秸,樹中的結(jié)點不僅包含左右子結(jié)點软能,同時包含指向父結(jié)點的指針迎捺。
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode==null) return null;
// 右節(jié)點不為空
if(pNode.right!=null)
{
// 找到右節(jié)點的最左節(jié)點
pNode=pNode.right;
while(pNode.left!=null)
{
pNode=pNode.left;
}
return pNode;
}
// 右節(jié)點為空,找到其為父節(jié)點的左節(jié)點的那個最近的父節(jié)點查排。
while(pNode.next!=null)
{
if(pNode.next.left==pNode) return pNode.next;
pNode=pNode.next;
}
return null;
}
}
58. 請實現(xiàn)一個函數(shù)凳枝,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的岖瑰,定義其為對稱的叛买。
public class Solution {
public boolean isSymmetrical(TreeNode pRoot) {
if(pRoot==null) return true;
return isSymmetrical(pRoot.left,pRoot.right);
}
public boolean isSymmetrical(TreeNode left, TreeNode right) {
if (left == null && right == null)
return true;
if (left == null || right == null)
return false;
if (left.val == right.val)
// 左左相比,右右相比蹋订,這是最核心的思想了率挣。
return isSymmetrical(left.left, right.right) && isSymmetrical(left.right, right.left);
return false;
}
}
59. 請實現(xiàn)一個函數(shù)按照之字形打印二叉樹,即第一行按照從左到右的順序打印露戒,第二層按照從右至左的順序打印椒功,第三行按照從左到右的順序打印,其他行以此類推智什。
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
if(pRoot==null){
return res;
}
ArrayList<Integer> list;
Queue<TreeNode> queue=new LinkedList<TreeNode>();
int rows=1;
queue.add(pRoot);
while(!queue.isEmpty()){
list=new ArrayList<>();
int size=queue.size();
for(int i=0;i<size;i++){
TreeNode t=queue.poll();
// 分層考慮
if(rows%2==0){
list.add(0,t.val); // 每次都插入到最前面
}else{
list.add(t.val);
}
if(t.left!=null){
queue.offer(t.left);
}
if(t.right!=null){
queue.offer(t.right);
}
}
res.add(list);
rows++;
}
return res;
}
}
60. 從上到下按層打印二叉樹动漾,同一層結(jié)點從左至右輸出。每一層輸出一行荠锭。
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer> > result = new ArrayList<>();
if(pRoot == null) {
return result;
}
ArrayList<TreeNode> nodes = new ArrayList<>();
nodes.add(pRoot);
Print(result, nodes);
return result;
}
public void Print(ArrayList<ArrayList<Integer> > result, ArrayList<TreeNode> nodes) {
if(!nodes.isEmpty()) {
ArrayList<Integer> temp = new ArrayList<>();
ArrayList<TreeNode> next = new ArrayList<>();
for(TreeNode t : nodes) {
temp.add(t.val);
if(t.left != null) {
next.add(t.left);
}
if(t.right != null) {
next.add(t.right);
}
}
result.add(temp);
Print(result, next);
}
}
}
注解:借助隊列會更好做吧
62. 給定一棵二叉搜索樹旱眯,請找出其中的第k小的結(jié)點。例如证九, (5删豺,3,7愧怜,2吼鳞,4,6叫搁,8) 中赔桌,按結(jié)點數(shù)值大小順序第三小結(jié)點的值為4。
public class Solution {
int index = 0;
TreeNode KthNode(TreeNode root, int k) {
if (root != null) { // 中序遍歷尋找第k個
TreeNode node = KthNode(root.left, k);
if (node != null)
return node;
index++;
if (index == k)
return root;
node = KthNode(root.right, k);
if (node != null)
return node;
}
return null;
}
}
63. 如何得到一個數(shù)據(jù)流中的中位數(shù)渴逻?如果從數(shù)據(jù)流中讀出奇數(shù)個數(shù)值疾党,那么中位數(shù)就是所有數(shù)值排序之后位于中間的數(shù)值。如果從數(shù)據(jù)流中讀出偶數(shù)個數(shù)值惨奕,那么中位數(shù)就是所有數(shù)值排序之后中間兩個數(shù)的平均值雪位。我們使用Insert()方法讀取數(shù)據(jù)流,使用GetMedian()方法獲取當前讀取數(shù)據(jù)的中位數(shù)梨撞。
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
ArrayList<Integer> al = new ArrayList<Integer>();
public void Insert(Integer num) {
al.add(num);
Collections.sort(al);
}
public Double GetMedian() {
int mid = al.size() / 2;
if ((al.size() & 1) == 0) {
Integer n1 = al.get(mid);
Integer n2 = al.get(mid - 1);
double s = (Double.valueOf(n1 + "") + Double.valueOf(n2 + "")) / 2;
return s;
} else {
double s = Double.valueOf(al.get(mid) + "");
return s;
}
}
}
65. 請設計一個函數(shù)雹洗,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始卧波,每一步可以在矩陣中向左时肿,向右,向上港粱,向下移動一個格子螃成。如果一條路徑經(jīng)過了矩陣中的某一個格子旦签,則之后不能再次進入這個格子。 例如 a b c e s f c s a d e e 這樣的3 X 4 矩陣中包含一條字符串"bcced"的路徑寸宏,但是矩陣中不包含"abcb"路徑宁炫,因為字符串的第一個字符b占據(jù)了矩陣中的第一行第二個格子之后,路徑不能再次進入該格子氮凝。
public class Solution {
// 65
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
int []flag=new int[matrix.length];
// 可選開始值
for(int i=0;i<rows;i++) {
for(int j=0;j<cols;j++) {
if(hasPath(matrix,rows,cols,i,j,0,str,flag))
return true;
}
}
return false;
}
public boolean hasPath(char[]matrix,int rows,int cols,int i,int j,int k,char[]str,int[]flag)
{
int index=i*cols+j;
if(i<0||i>=rows||j<0||j>=cols||flag[index]==1||matrix[index]!=str[k])return false;
if(k==str.length-1) return true;
flag[index]=1;
// 核心遍歷
if(hasPath(matrix,rows,cols,i+1,j,k+1,str,flag)||hasPath(matrix,rows,cols,i-1,j,k+1,str,flag)||hasPath(matrix,rows,cols,i,j+1,k+1,str,flag)||hasPath(matrix,rows,cols,i,j-1,k+1,str,flag))
return true;
flag[index]=0;
return false;
}
}
66. 地上有一個m行和n列的方格羔巢。一個機器人從坐標0,0的格子開始移動,每一次只能向左罩阵,右朵纷,上,下四個方向移動一格永脓,但是不能進入行坐標和列坐標的數(shù)位之和大于k的格子袍辞。 例如,當k為18時常摧,機器人能夠進入方格(35,37)搅吁,因為3+5+3+7 = 18。但是落午,它不能進入方格(35,38)谎懦,因為3+5+3+8 = 19。請問該機器人能夠達到多少個格子溃斋?
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
boolean[] visited=new boolean[rows*cols];
// 與上一題相比界拦,課題初始值只有一個
return movingCountCore(threshold, rows, cols, 0,0,visited);
}
private int movingCountCore(int threshold, int rows, int cols,
int row,int col,boolean[] visited) {
if(row<0||row>=rows||col<0||col>=cols) return 0;
int i=row*cols+col;
if(visited[i]||!checkSum(threshold,row,col)) return 0;
visited[i]=true;
// 這里保持統(tǒng)一,而在返回推薦控制越界梗劫。
return 1+movingCountCore(threshold, rows, cols,row,col+1,visited)
+movingCountCore(threshold, rows, cols,row,col-1,visited)
+movingCountCore(threshold, rows, cols,row+1,col,visited)
+movingCountCore(threshold, rows, cols,row-1,col,visited);
}
//指定規(guī)則
private boolean checkSum(int threshold, int row, int col) {
int sum=0;
while(row!=0){
sum+=row%10;
row=row/10;
}
while(col!=0){
sum+=col%10;
col=col/10;
}
if(sum>threshold) return false;
return true;
}
}