摘要:這一部分主要是資料結構和算法相關的面試題目,雖然隻有15道題目,但是包含的資訊量還是很大的,很多題目背後的解題思路和算法是非常值得玩味的。
136、給出下面的二叉樹先序、中序、後序周遊的序列?

答:先序序列:ABDEGHCF;中序序列:DBGEHACF;後序序列:DGHEBFCA。
補充:二叉樹也稱為二分樹,它是樹形結構的一種,其特點是每個結點至多有二棵子樹,并且二叉樹的子樹有左右之分,其次序不能任意颠倒。二叉樹的周遊序列按照通路根節點的順序分為先序(先通路根節點,接下來先序通路左子樹,再先序通路右子樹)、中序(先中序通路左子樹,然後通路根節點,最後中序通路右子樹)和後序(先後序通路左子樹,再後序通路右子樹,最後通路根節點)。如果知道一棵二叉樹的先序和中序序列或者中序和後序序列,那麼也可以還原出該二叉樹。
例如,已知二叉樹的先序序列為:xefdzmhqsk,中序序列為:fezdmxqhks,那麼還原出該二叉樹應該如下圖所示:
137、你知道的排序算法都哪些?用Java寫一個排序系統。
答:穩定的排序算法有:插入排序、選擇排序、冒泡排序、雞尾酒排序、歸并排序、二叉樹排序、基數排序等;不穩定排序算法包括:希爾排序、堆排序、快速排序等。
下面是關于排序算法的一個清單:
下面按照政策模式給出一個排序系統,實作了冒泡、歸并和快速排序。
Sorter.java
[java]
view plain
copy
- package com.jackfrued.util;
- import java.util.Comparator;
- /**
- * 排序器接口(政策模式: 将算法封裝到具有共同接口的獨立的類中使得它們可以互相替換)
- * @author駱昊
- *
- */
- public interface Sorter {
- /**
- * 排序
- * @param list 待排序的數組
- */
- public <T extends Comparable<T>> void sort(T[] list);
- /**
- * 排序
- * @param list 待排序的數組
- * @param comp 比較兩個對象的比較器
- */
- public <T> void sort(T[] list, Comparator<T> comp);
- }
BubbleSorter.java
[java]
view plain
copy
- package com.jackfrued.util;
- import java.util.Comparator;
- /**
- * 冒泡排序
- * @author駱昊
- *
- */
- public class BubbleSorter implements Sorter {
- @Override
- public <T extends Comparable<T>> void sort(T[] list) {
- boolean swapped = true;
- for(int i = 1; i < list.length && swapped;i++) {
- false;
- for(int j = 0; j < list.length - i; j++) {
- if(list[j].compareTo(list[j+ 1]) > 0 ) {
- T temp = list[j];
- 1];
- 1] = temp;
- true;
- }
- }
- }
- }
- @Override
- public <T> void sort(T[] list,Comparator<T> comp) {
- boolean swapped = true;
- for(int i = 1; i < list.length && swapped; i++) {
- false;
- for(int j = 0; j < list.length - i; j++) {
- if(comp.compare(list[j], list[j + 1]) > 0 ) {
- T temp = list[j];
- 1];
- 1] = temp;
- true;
- }
- }
- }
- }
- }
MergeSorter.java
[java]
view plain
copy
- package com.jackfrued.util;
- import java.util.Comparator;
- /**
- * 歸并排序
- * 歸并排序是建立在歸并操作上的一種有效的排序算法。
- * 該算法是采用分治法(divide-and-conquer)的一個非常典型的應用,
- * 先将待排序的序列劃分成一個一個的元素,再進行兩兩歸并,
- * 在歸并的過程中保持歸并之後的序列仍然有序。
- * @author駱昊
- *
- */
- public class MergeSorter implements Sorter {
- @Override
- public <T extends Comparable<T>> void sort(T[] list) {
- new Comparable[list.length];
- 0, list.length- 1);
- }
- private <T extends Comparable<T>> void mSort(T[] list, T[] temp, int low, int high) {
- if(low == high) {
- return ;
- }
- else {
- int mid = low + ((high -low) >> 1);
- mSort(list,temp, low, mid);
- 1, high);
- 1, high);
- }
- }
- private <T extends Comparable<T>> void merge(T[] list, T[] temp, int left, int right, int last) {
- int j = 0;
- int lowIndex = left;
- int mid = right - 1;
- int n = last - lowIndex + 1;
- while (left <= mid && right <= last){
- if (list[left].compareTo(list[right]) < 0){
- temp[j++] = list[left++];
- else {
- temp[j++] = list[right++];
- }
- }
- while (left <= mid) {
- temp[j++] = list[left++];
- }
- while (right <= last) {
- temp[j++] = list[right++];
- }
- for (j = 0; j < n; j++) {
- list[lowIndex + j] = temp[j];
- }
- }
- @Override
- public <T> void sort(T[] list, Comparator<T> comp) {
- new Comparable[list.length];
- 0, list.length- 1, comp);
- }
- private <T> void mSort(T[] list, T[] temp, int low, int high, Comparator<T> comp) {
- if(low == high) {
- return ;
- }
- else {
- int mid = low + ((high -low) >> 1);
- mSort(list,temp, low, mid, comp);
- 1, high, comp);
- 1, high, comp);
- }
- }
- private <T> void merge(T[] list, T[]temp, int left, int right, int last, Comparator<T> comp) {
- int j = 0;
- int lowIndex = left;
- int mid = right - 1;
- int n = last - lowIndex + 1;
- while (left <= mid && right <= last){
- if (comp.compare(list[left], list[right]) <0) {
- temp[j++] = list[left++];
- else {
- temp[j++] = list[right++];
- }
- }
- while (left <= mid) {
- temp[j++] = list[left++];
- }
- while (right <= last) {
- temp[j++] = list[right++];
- }
- for (j = 0; j < n; j++) {
- list[lowIndex + j] = temp[j];
- }
- }
- }
QuickSorter.java
[java]
view plain
copy
- package com.jackfrued.util;
- import java.util.Comparator;
- /**
- * 快速排序
- * 快速排序是使用分治法(divide-and-conquer)依標明的樞軸
- * 将待排序序列劃分成兩個子序列,其中一個子序列的元素都小于樞軸,
- * 另一個子序列的元素都大于或等于樞軸,然後對子序列重複上面的方法,
- * 直到子序列中隻有一個元素為止
- * @author Hao
- *
- */
- public class QuickSorter implements Sorter {
- @Override
- public <T extends Comparable<T>> void sort(T[] list) {
- 0, list.length- 1);
- }
- @Override
- public <T> void sort(T[] list, Comparator<T> comp) {
- 0, list.length- 1, comp);
- }
- private <T extends Comparable<T>> void quickSort(T[] list, int first, int last) {
- if (last > first) {
- int pivotIndex = partition(list, first, last);
- 1);
- quickSort(list, pivotIndex, last);
- }
- }
- private <T> void quickSort(T[] list, int first, int last,Comparator<T> comp) {
- if (last > first) {
- int pivotIndex = partition(list, first, last, comp);
- 1, comp);
- quickSort(list, pivotIndex, last, comp);
- }
- }
- private <T extends Comparable<T>> int partition(T[] list, int first, int last) {
- T pivot = list[first];
- int low = first + 1;
- int high = last;
- while (high > low) {
- while (low <= high && list[low].compareTo(pivot) <= 0) {
- low++;
- }
- while (low <= high && list[high].compareTo(pivot) >= 0) {
- high--;
- }
- if (high > low) {
- T temp = list[high];
- list[high]= list[low];
- list[low]= temp;
- }
- }
- while (high > first&& list[high].compareTo(pivot) >= 0) {
- high--;
- }
- if (pivot.compareTo(list[high])> 0) {
- list[first]= list[high];
- list[high]= pivot;
- return high;
- }
- else {
- return low;
- }
- }
- private <T> int partition(T[] list, int first, int last, Comparator<T> comp) {
- T pivot = list[first];
- int low = first + 1;
- int high = last;
- while (high > low) {
- while (low <= high&& comp.compare(list[low], pivot) <= 0) {
- low++;
- }
- while (low <= high&& comp.compare(list[high], pivot) >= 0) {
- high--;
- }
- if (high > low) {
- T temp = list[high];
- list[high] = list[low];
- list[low]= temp;
- }
- }
- while (high > first&& comp.compare(list[high], pivot) >= 0) {
- high--;
- }
- if (comp.compare(pivot,list[high]) > 0) {
- list[first]= list[high];
- list[high]= pivot;
- return high;
- }
- else {
- return low;
- }
- }
- }
138、寫一個二分查找(折半搜尋)的算法。
答:折半搜尋,也稱二分查找算法、二分搜尋,是一種在有序數組中查找某一特定元素的搜尋算法。搜素過程從數組的中間元素開始,如果中間元素正好是要查找的元素,則搜素過程結束;如果某一特定元素大于或者小于中間元素,則在數組大于或小于中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。如果在某一步驟數組為空,則代表找不到。這種搜尋算法每一次比較都使搜尋範圍縮小一半。
[java]
view plain
copy
- package com.jackfrued.util;
- import java.util.Comparator;
- public class MyUtil {
- public static <T extends Comparable<T>> int binarySearch(T[] x, T key) {
- return binarySearch(x, 0, x.length- 1, key);
- }
- public static <T> int binarySearch(T[] x, T key, Comparator<T> comp) {
- int low = 0;
- int high = x.length - 1;
- while (low <= high) {
- int mid = (low + high) >>> 1;
- int cmp = comp.compare(x[mid], key);
- if (cmp < 0) {
- 1;
- }
- else if (cmp > 0) {
- 1;
- }
- else {
- return mid;
- }
- }
- return -1;
- }
- private static <T extends Comparable<T>> int binarySearch(T[] x, int low, int high, T key) {
- if(low <= high) {
- int mid = low + ((high -low) >> 1);
- if(key.compareTo(x[mid]) == 0) {
- return mid;
- }
- else if(key.compareTo(x[mid])< 0) {
- return binarySearch(x,l ow, mid - 1, key);
- }
- else {
- return binarySearch(x, mid + 1, high, key);
- }
- }
- return -1;
- }
- }
說明:兩個版本一個用遞歸實作,一個用循環實作。需要注意的是計算中間位置時不應該使用(high+ low) / 2的方式,因為加法運算可能導緻整數越界,這裡應該使用一下三種方式之一:low+ (high – low) / 2或low + (high – low) >> 1或(low + high) >>> 1(注:>>>是邏輯右移,不帶符号位的右移)
139、統計一篇英文文章中單詞個數。
答:
[java]
view plain
copy
- import java.io.FileReader;
- public class WordCounting {
- public static void main(String[] args) {
- try(FileReader fr = new FileReader("a.txt")) {
- int counter = 0;
- boolean state = false;
- int currentChar;
- while((currentChar= fr.read()) != -1) {
- if(currentChar== ' ' || currentChar == '\n'
- '\t' || currentChar == '\r') {
- false;
- }
- else if(!state) {
- true;
- counter++;
- }
- }
- System.out.println(counter);
- }
- catch(Exceptione) {
- e.printStackTrace();
- }
- }
- }
補充:這個程式可能有很多種寫法,這裡選擇的是Dennis M. Ritchie和Brian W. Kernighan老師在他們不朽的著作《The C Programming Language》中給出的代碼,向兩位老師緻敬。下面的代碼也是如此。
140、輸入年月日,計算該日期是這一年的第幾天。
答:
[java]
view plain
copy
- import java.util.Scanner;
- public class DayCounting {
- public static void main(String[] args) {
- int[][] data = {
- 31,28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
- 31,29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
- };
- Scanner sc = newScanner(System.in);
- "請輸入年月日(1980 11 28): ");
- int year = sc.nextInt();
- int month = sc.nextInt();
- int date = sc.nextInt();
- int[] daysOfMonth = data[(year % 4 == 0 && year % 100 != 0 || year % 400 == 0)?1 : 0];
- int sum = 0;
- for(int i = 0; i < month -1; i++) {
- sum += daysOfMonth[i];
- }
- sum += date;
- System.out.println(sum);
- sc.close();
- }
- }
141、約瑟夫環:15個基督教徒和15個非教徒在海上遇險,必須将其中一半的人投入海中,其餘的人才能幸免于難,于是30個人圍成一圈,從某一個人開始從1報數,報到9的人就扔進大海,他後面的人繼續從1開始報數,重複上面的規則,直到剩下15個人為止。結果由于上帝的保佑,15個基督教徒最後都幸免于難,問原來這些人是怎麼排列的,哪些位置是基督教徒,哪些位置是非教徒。
答:
[java]
view plain
copy
- public class Josephu {
- private static final int DEAD_NUM = 9;
- public static void main(String[] args) {
- boolean[] persons = new boolean[30];
- for(int i = 0; i < persons.length; i++) {
- true;
- }
- int counter = 0;
- int claimNumber = 0;
- int index = 0;
- while(counter < 15) {
- if(persons[index]) {
- claimNumber++;
- if(claimNumber == DEAD_NUM) {
- counter++;
- 0;
- false;
- }
- }
- index++;
- if(index >= persons.length) {
- 0;
- }
- }
- for(boolean p : persons) {
- if(p) {
- "基");
- }
- else {
- "非");
- }
- }
- }
- }
142、回文素數:所謂回文數就是順着讀和倒着讀一樣的數(例如:11,121,1991…),回文素數就是既是回文數又是素數(隻能被1和自身整除的數)的數。程式設計找出11~9999之間的回文素數。
答:
[java]
view plain
copy
- public class PalindromicPrimeNumber {
- public static void main(String[] args) {
- for(int i = 11; i <= 9999; i++) {
- if(isPrime(i) && isPalindromic(i)) {
- System.out.println(i);
- }
- }
- }
- public static boolean isPrime(int n) {
- for(int i = 2; i <= Math.sqrt(n); i++) {
- if(n % i == 0) {
- return false;
- }
- }
- return true;
- }
- public static boolean isPalindromic(int n) {
- int temp = n;
- int sum = 0;
- while(temp > 0) {
- 10 + temp % 10;
- 10;
- }
- return sum == n;
- }
- }
143、全排列:給出五個數字12345的所有排列。
答:
[java]
view plain
copy
- public class FullPermutation {
- public static void perm(int[] list) {
- 0);
- }
- private static void perm(int[] list, int k) {
- if (k == list.length) {
- for (int i = 0; i < list.length; i++) {
- System.out.print(list[i]);
- }
- System.out.println();
- else{
- for (int i = k; i < list.length; i++) {
- swap(list, k, i);
- 1);
- swap(list, k, i);
- }
- }
- }
- private static void swap(int[] list, int pos1, int pos2) {
- int temp = list[pos1];
- list[pos1] = list[pos2];
- list[pos2] = temp;
- }
- public static void main(String[] args) {
- int[] x = {1, 2, 3, 4, 5};
- perm(x);
- }
- }
144、對于一個有N個整數元素的一維數組,找出它的子數組(數組中下标連續的元素組成的數組)之和的最大值。
答:下面給出幾個例子(最大子數組用粗體表示):
1) 數組:{ 1, -2, 3,5, -3, 2 },結果是:8
2) 數組:{ 0, -2, 3, 5, -1, 2 },結果是:9
3) 數組:{ -9, -2,-3, -5, -3 },結果是:-2
可以使用動态規劃的思想求解:
[java]
view plain
copy
- public class MaxSum {
- private static int max(int x, int y) {
- return x > y? x: y;
- }
- public static int maxSum(int[] array) {
- int n = array.length;
- int[] start = new int[n];
- int[] all = new int[n];
- 1] = start[n - 1] = array[n - 1];
- for(int i = n - 2; i >= 0;i--) {
- 1]);
- 1]);
- }
- return all[0];
- }
- public static void main(String[] args) {
- int[] x1 = { 1, -2, 3, 5,-3, 2 };
- int[] x2 = { 0, -2, 3, 5,-1, 2 };
- int[] x3 = { -9, -2, -3,-5, -3 };
- // 8
- // 9
- //-2
- }
- }
145、用遞歸實作字元串倒轉
答:
[java]
view plain
copy
- public class StringReverse {
- public static String reverse(String originStr) {
- if(originStr == null || originStr.length()== 1) {
- return originStr;
- }
- return reverse(originStr.substring(1))+ originStr.charAt(0);
- }
- public static void main(String[] args) {
- "hello"));
- }
- }
146、輸入一個正整數,将其分解為素數的乘積。
答:
[java]
view plain
copy
- public class DecomposeInteger {
- private static List<Integer> list = newArrayList<Integer>();
- public static void main(String[] args) {
- "請輸入一個數: ");
- Scanner sc = newScanner(System.in);
- int n = sc.nextInt();
- decomposeNumber(n);
- " = ");
- for(int i = 0; i < list.size() - 1; i++) {
- " * ");
- }
- 1));
- }
- public static void decomposeNumber(int n) {
- if(isPrime(n)) {
- list.add(n);
- 1);
- }
- else {
- int)Math.sqrt(n));
- }
- }
- public static void doIt(int n, int div) {
- if(isPrime(div) && n % div == 0) {
- list.add(div);
- decomposeNumber(n / div);
- }
- else {
- 1);
- }
- }
- public static boolean isPrime(int n) {
- for(int i = 2; i <= Math.sqrt(n);i++) {
- if(n % i == 0) {
- return false;
- }
- }
- return true;
- }
- }
147、一個有n級的台階,一次可以走1級、2級或3級,問走完n級台階有多少種走法。
答:可以通過遞歸求解。
[java]
view plain
copy
- public class GoSteps {
- public static int countWays(int n) {
- if(n < 0) {
- return 0;
- }
- else if(n == 0) {
- return 1;
- }
- else {
- return countWays(n - 1) + countWays(n - 2) + countWays(n -3);
- }
- }
- public static void main(String[] args) {
- 5)); // 13
- }
- }
148、寫一個算法判斷一個英文單詞的所有字母是否全都不同(不區分大小寫)。
答:
[java]
view plain
copy
- public class AllNotTheSame {
- public static boolean judge(String str) {
- String temp = str.toLowerCase();
- int[] letterCounter = new int[26];
- for(int i = 0; i <temp.length(); i++) {
- int index = temp.charAt(i)- 'a';
- letterCounter[index]++;
- if(letterCounter[index] > 1) {
- return false;
- }
- }
- return true;
- }
- public static void main(String[] args) {
- "hello"));
- "smile"));
- }
- }
149、有一個已經排好序的整數數組,其中存在重複元素,請将重複元素删除掉,例如,A= [1, 1, 2, 2, 3],處理之後的數組應當為A= [1, 2, 3]。
答:
[java]
view plain
copy
- import java.util.Arrays;
- public class RemoveDuplication {
- public static int[] removeDuplicates(int a[]) {
- if(a.length <= 1) {
- return a;
- }
- int index = 0;
- for(int i = 1; i < a.length; i++) {
- if(a[index] != a[i]) {
- a[++index] = a[i];
- }
- }
- int[] b = new int[index + 1];
- 0, b, 0, b.length);
- return b;
- }
- public static void main(String[] args) {
- int[] a = {1, 1, 2, 2, 3};
- a = removeDuplicates(a);
- System.out.println(Arrays.toString(a));
- }
- }
150、給一個數組,其中有一個重複元素占半數以上,找出這個元素。
答:
[java]
view plain
copy
- public class FindMost {
- public static <T> T find(T[] x){
- null;
- for(int i = 0, nTimes = 0; i< x.length;i++) {
- if(nTimes == 0) {
- temp= x[i];
- 1;
- }
- else {
- if(x[i].equals(temp)) {
- nTimes++;
- }
- else {
- nTimes--;
- }
- }
- }
- return temp;
- }
- public static void main(String[] args) {
- "hello","kiss","hello","hello","maybe"};
- System.out.println(find(strs));
- }
- }