劍指offer解題記錄

面試題3:數組中重複的數字

題目鏈接

 

import java.util.Arrays;

/**
 * P39 面試題3:數組中重複的數字
 * 在一個長度爲n的數組裏所有數字都在0~n-1的範圍內 數組中某些數字是重複的 但不知道有幾個數字重複了
 * 也不知道每個數字重複了幾次 請找出數組中任意一個重複的數字
 * 例如 如果輸入長度爲7的數組{2,3,1,0,2,5,3}
 * 那麼對應的輸出是重複的數字2或者3
 * @author tzy
 *
 */


public class T3
{
	public static void main(String[] args)
	{
		int[] duplication=new int[1];  //保存答案的數組 結果保存在[0]
		int[] inputarr={11,22,1,0,2,5,5};

		
	}
	
	/*
	 * 解法1:排序數組後找到重複值
	 * 排序算法的時間複雜度爲O(nlogn)
	 */
	public static boolean solution1(int[] numbers,int length,int[] duplication)
	{
		if(numbers==null||length<=0)
		{
			return false;
		}
		Arrays.parallelSort(numbers);
		for(int i=0;i<numbers.length-1;i++)
		{
			if(numbers[i]==numbers[i+1])
			{
				duplication[0]=numbers[i];
				return true;
			}
		}
		return false;
	}
	
	/*
	 * 解法2:使用哈希表
	 * 時間複雜度O(N) 空間複雜度O(N)
	 */
	public static boolean solution2(int[] numbers,int length,int[] duplication)
	{
		int temp[]=new int[length+1];
		if(numbers==null||length<=0)
		{
			return false;
		}
		for(int i=0;i<length;i++)
		{
			temp[numbers[i]]++;
		}
		for(int j=0;j<length;j++)
		{
			if(temp[j]>1)
			{
				duplication[0]=j;
				return true;
			}
		}
		return false;
	}
	
	/*
	 * 解法3 推薦解法
	 * 時間複雜度O(N) 空間複雜度O(1)
	 * 通過將下標爲i的數字(稱爲m)調整到屬於它的下標的位置
	 */
	public static boolean solution3(int[] numbers,int length,int[] duplication)
	{
		if(numbers==null||length<=0)
		{
			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;
	}
}

面試題4:二維數組中的查找

題目鏈接

/*
 * P44面試題4:二維數組中的查找
 * 題目:在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序
 * 請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數
 */
public class T4
{
	/*
	 * 思路:對於二維數組中的每一個數字,他小於他右邊的數字,小於他下方的數字
	 * 所以從右上角的數字(稱爲m)開始查找 
	 * 若m>target 則剔除m所在的列 因爲m是這一列最小的元素 這一列所有的元素將大於target
	 * 若m<target 則剔除m所在的行 因爲m是這一行最小的元素 這一行所有的元素將小於target
	 */
	public boolean Find(int target, int [][] array) 
	{
		if(array.length==0||array[0].length==0||array==null)
		{
			return false;
		}
		//記錄行數與列數
		int rows=array.length;
		int cols=array[0].length;
		//從右上角開始搜索
		int rownow=0;
		int colnow=cols-1;
		while(rownow<=rows-1&&colnow>=0)//搜索到最左下角的數字是邊界條件
		{
			if(array[rownow][colnow]==target)
			{
				return true;
			}
			else if(array[rownow][colnow]>target)
			{
				colnow--;
			}
			else
			{
				rownow++;
			}
		}
		return false;
    }
}

面試題5:替換空格

題目鏈接

/*
 * P51面試題5:替換空格
 * 題目:請實現一個函數,把字符串中的每個空格替換成"%20"
 * 例如輸入"We are happy."
 * 則輸出"We%20are%20happy."
 */
public class T5
{
	/*
	 * 解題思路:
	 * 先遍歷一遍數組 找到一共有多少個空格 在尾部添加2*空格個數的任意字符
	 * 令P1指向原末尾,P2指向延長後的末尾,兩指針均從後往前遍歷(P1開始)
	 * 每當P1遍歷到一個字符時 將它複製到P2 兩指針同時前移一位
	 * 當P1遍歷到空格時 P1向前移一位 P2向前移動三位並填充02%
	 * 當P1與P2重合時 則結束
	 * 從後向前遍歷是爲了在改變P2所指向的內容時 不會影響到P1遍歷原來的字符串內容 
	 */
	public String replaceSpace(StringBuffer str) 
	 {
		 int P1=str.length()-1;
		 for(int i=0;i<=P1;i++)
		 {
			 if(str.charAt(i)==' ')
			 {
				 str.append("  ");
			 }
		 }
		 int P2=str.length()-1;
		 while(P1!=P2)
		 {
			 if(str.charAt(P1)!=' ')
			 {
				 str.setCharAt(P2, str.charAt(P1));
				 P1--;
				 P2--;
			 }
			 else
			 {
				 P1--;
				 str.setCharAt(P2--, '0');
				 str.setCharAt(P2--, '2');
				 str.setCharAt(P2--, '%');
			 }
		 }
		 return str.toString();
	 }
}

面試題6:從尾到頭打印鏈表

題目鏈接

import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

/*
 * P58面試題6:從尾到頭打印鏈表
 * 題目:輸入一個鏈表的頭結點,從尾到頭反過來打印出每個節點的值
 */
public class T6
{
	/*
	 * 解法一:使用棧
	 * 由於棧的“後進先出特性” 對鏈表進行一次遍歷後依次彈出
	 * 得到的順序即爲逆序
	 */
	public ArrayList<Integer> printListFromTailToHead1(ListNode listNode) 
	{
		Stack<Integer> stack=new Stack<Integer>();
		while(listNode!=null)
		{
			stack.add(listNode.val);
			listNode=listNode.next;
		}
		ArrayList<Integer> res=new ArrayList<Integer>();
		while(!stack.isEmpty())
		{
			res.add(stack.pop());
		}
		return res;
    }
	
	/*
	 * 解法二:使用遞歸
	 * 遞歸的本質就是一個棧結構 所以可以自然地想到用遞歸來實現
	 * 具體實現爲:每訪問到一個節點的時候,先遞歸輸出它後面的節點,再輸出該節點自身
	 * 但該方法若是輸入的鏈表長度非常長時
	 * 會導致函數調用的層級過深
	 * 從而導致函數調用棧溢出(java.lang.StackOverflowError)
	 */
	public ArrayList<Integer> printListFromTailToHead2(ListNode listNode) 
	{
		ArrayList<Integer> res=new ArrayList<Integer>();
		if(listNode!=null)
		{
			res.addAll(printListFromTailToHead2(listNode.next));
			res.add(listNode.val);
		}
		return res;
	}
	
	/*
	 * 解法三:使用頭插法
	 * 由於頭插法的性質是每次插入在頭部
	 * 所以使用頭插法重新構建鏈表後即爲逆序
	 * 注意點:
	 * 頭結點是在頭插法中使用的一個額外節點,這個節點不存儲值
	 * 第一個節點就是鏈表的第一個真正存儲值的節點
	 */
	public ArrayList<Integer> printListFromTailToHead3(ListNode listNode) 
	{
		ListNode head=new ListNode(-1);//頭結點
		while(listNode!=null)
		{
			ListNode temp=new ListNode(listNode.val);
			temp.next=head.next;
			head.next=temp;
			listNode=listNode.next;
		}	
		ArrayList<Integer> res=new ArrayList<Integer>();
		head=head.next;
		while(head!=null)
		{
			res.add(head.val);
			head=head.next;
		}
		return res;
	}
	
	
	/*
	 * 解法四:使用Collection.reverse()
	 */
	public ArrayList<Integer> printListFromTailToHead4(ListNode listNode) 
	{
		ArrayList<Integer> res=new ArrayList<Integer>();
		while(listNode!=null)
		{
			res.add(listNode.val);
			listNode=listNode.next;
		}
		Collections.reverse(res);
		return res;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章