劍指Offer演算法題JAVA版13-20題(全是個人寫的非官方,只供參考和自己複習,測試用例都通過了。)
13.調整陣列順序使奇數位於偶數前面
輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有的奇數位於陣列的前半部分,所有的偶數位於位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。
(思路:是一個類似與快速排序,的思路,但快速排序是不穩定的。要保證,偶數和基數的相對位置穩定)
14.連結串列中倒數第k個結點public void reOrderArray(int [] array) { int n=0;//指向要被交換的位置,始終位於偶數串的第一位 int k=0;//記錄連續的偶數串長度 for(int i=0;i<array.length;i++){//其中i就是遍歷整個陣列,走到偶數,就繼續往前走,並記錄走過偶數的個數,遇到奇數就將該基數,放到n所在位置,然後將整個偶數串後移一位。 if((array[i]&1)==0){//計算遍歷到i位置,一共有多少個偶數 k++;// } if((array[i]&1)==1){//當為級數 int t=array[i]; int p=k; while(p>0){//偶數串總體移動,保持相對位置不變 array[n+p]=array[n+p-1];//整個偶數串,向後移。 p--; } array[n]=t;//把奇數和需要被交換的位置 n++;//被交換位置向前移動。 } } }
輸入一個連結串列,輸出該連結串列中倒數第k個結點。
(思路很簡單,兩個指標都指向頭節點,然後讓其中一個向前跑k-1次,然後,後邊的指標開始跟著跑,直到前面指標的next 是空,則後面指標的位置就是倒數第k個元素)
public ListNode FindKthToTail(ListNode head,int k) { ListNode p=head;//後起步的指標 ListNode pre=head;//先起步的指標 if(k<=0)return null;//非法的k while(k>1&&pre!=null){//讓pre先走k-1步, pre=pre.next; k--; } if(pre==null){//整個鏈不足k個,返回空 return null; }else{ while(pre.next!=null){//pre走k-1之後,p和pre一起走。 pre=pre.next; p=p.next; } return p; } }
15.反轉連結串列
輸入一個連結串列,反轉連結串列後,輸出連結串列的所有元素。
15.1(思路:將整個鏈放入一個棧,放完之後,出棧,然後根據出棧的順序重新連線一條鏈就好了)
public ListNode ReverseList(ListNode head) { Stack<ListNode> stack=new Stack<ListNode>(); while(head!=null){//全部放入棧 stack.push(head); head=head.next; } if(!stack.isEmpty()){//棧不為空的情況下 ListNode last=stack.pop();//last指標指向第一個出<span style="line-height: 25.2px; font-family: arial, STHeiti, 'Microsoft YaHei', 宋體;">棧</span>的元素 ListNode first=last;//新的first指標也指向第一個出棧的元素 while(!stack.isEmpty()){ last.next=stack.pop();//last的下一個元素等於下一個彈出的元素 last=last.next;//last指標指向最新的彈出的元素 } last.next=null;//迴圈之後,last位於最後一個元素,將最後一個元素的next置為空。 return first;//返回新連結串列的頭 }else{//棧為空,返回空 return null; } }
15.2用三個指標來,來操作,這樣節省空間。
public ListNode ReverseList(ListNode head) {
ListNode pre=null;
ListNode hnext=null;
while(head!=null){
hnext=head.next;
head.next=pre;
pre=head;
head=hnext;
}
return pre;
}
16.合併兩個排序的連結串列
輸入兩個單調遞增的連結串列,輸出兩個連結串列合成後的連結串列,當然我們需要合成後的連結串列滿足單調不減規則。
16.1非遞迴方法
(思路:思路較簡單)
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode list3=null;
ListNode listHead=null;
if(list1!=null&list2!=null){
if(list1.val<=list2.val){//將返回連結串列的頭指標放在兩個連結串列中值小的頭上。
list3=new ListNode(list1.val);
listHead=list3;
list1=list1.next;
}else if(list2.val<list1.val){
list3=new ListNode(list2.val);
listHead=list3;
list2=list2.next;
}
//一次迴圈,兩個連結串列元素一次比較,值較小的接到,返回連結串列後面,知道其中一個連結串列走完
while(list1!=null&&list2!=null){
if(list1.val<=list2.val){
list3.next=list1;
list3=list3.next;
list1=list1.next;
}else{
list3.next=list2;
list3=list3.next;
list2=list2.next;
}
}
if(list1==null){//將沒有遍歷完的連結串列的剩餘部分接到,返回連結串列的後面
list3.next=list2;
}else if(list2==null){
list3.next=list1;
}
return listHead;
}else if(list1==null&&list2!=null){
listHead=list2;
}else if(list2==null&&list1!=null){
listHead=list1;
}
return listHead;
}
16.2遞迴的方法
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null){
return list2;
}else if(list2==null){
return list1;
}
if(list1.val<=list2.val){
list1.next=Merge(list1.next,list2);
return list1;
}else{
list2.next=Merge(list1,list2.next);
return list2;
}
}
17.樹的子結構
輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1==null||root2==null){
return false;
}
if(root1.val==root2.val){//一旦當前節點相同,便呼叫<pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 22.4px;">isChildTree()方法,檢視root2是否是root1的子樹
boolean result=Solution.isChildTree(root1, root2);if(!result){boolean res1=HasSubtree(root1.right,root2);boolean res2=HasSubtree(root1.left, root2);return res2||res1;}else{return true;}}else{boolean res1=HasSubtree(root1.right,root2);boolean res2=HasSubtree(root1.left, root2);return res2||res1;} } public static boolean isChildTree(TreeNode root1,TreeNode root2){// 該方法用來判斷 兩個相同根的樹,root2是否是root1的子樹 boolean result=false; if(root2==null){ return true; }else if(root1==null){ return false; } if(root1.val!=root2.val){ return false; }else{boolean res1= isChildTree(root1.right,root2.right);boolean re2=isChildTree(root1.left, root2.left);result=res1&&re2;return result; } } 18.二叉樹的映象 操作給定的二叉樹,將其變換為源二叉樹的映象。
輸入描述:
二叉樹的映象定義:源二叉樹 8 / \ 6 10 / \ / \ 5 7 9 11 映象二叉樹 8 / \ 10 6 / \ / \ 11 9 7 5
public void Mirror(TreeNode root) {
if(root!=null){
Mirror(root.left);
Mirror(root.right);
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
}
}
19.順時針列印矩陣
輸入一個矩陣,按照從外向裡以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list=new ArrayList<Integer>();
if(matrix.length==0){
return null;
}else if(matrix.length==1){
for(int j=0;j<matrix[0].length;j++){
list.add(matrix[0][j]);
}
}else if(matrix[0].length==1){
for(int i=0;i<matrix.length;i++){
list.add(matrix[i][0]);
}
}else{
int k=matrix.length<=matrix[0].length?matrix.length:matrix[0].length;
double t=((double)k)/2;
int x=0;
while(t>0){
if(k-x*2>1){
for(int i=x;i<matrix[0].length-x-1;i++){
list.add(matrix[x][i]);
}
for(int i=x;i<matrix.length-x-1;i++){
list.add(matrix[i][matrix[0].length-x-1]);
}
for(int i=matrix[0].length-x-1;i>x;i--){
list.add(matrix[matrix.length-x-1][i]);
}
for(int i=matrix.length-x-1;i>x;i--){
list.add(matrix[i][x]);
}
x++;
t--;
}else{
if(matrix.length>=matrix[0].length){
for(int i=x;i<matrix.length-x;i++){
list.add(matrix[i][x]);
}
}else{
for(int i=x;i<matrix[0].length-x;i++){
list.add(matrix[x][i]);
}
}
x++;
t--;
}
}
}
return list;
}
20.包含min函式的棧
定義棧的資料結構,請在該型別中實現一個能夠得到棧最小元素的min函式。
(思路:一個min棧用來儲存當前最小的數,該棧棧頂始終是當前最小。出棧操作的時候,判斷當前最小元素被彈出,若當前最小彈出,那麼min棧也彈出,此時當前最小,依舊是min棧的棧頂)
public class Solution {
Stack<Integer> stack=new Stack<Integer>();
Stack<Integer> min =new Stack<Integer>();
public void push(int node) {
int minn=Integer.MAX_VALUE;
if(!min.isEmpty()){
minn=min.peek();
}
stack.push(node);
if(node<=minn){
minn=node;
min.push(node);
}
}
public void pop() {
int i=stack.pop();
if(i==min.peek()){
min.pop();
}
}
public int top() {
return stack.peek();
}
public int min() {
return min.peek();
}
}