我們在面試Android開發崗位時;不僅會面試許多技術問題,還常會問到一些算法題目,那麼這期就來解答這幾種常見算法題。
Android常見算法題
1、排序算法
快排
從平均時間來看,快速排序是效率最高的,但快速排序在最壞情況下的時間性能不如堆排序和歸併排序。
每次找個基數,然後對比基數,l 和 h 指針, 從兩頭開始找比自己小向右移,比自己大的向左移。
public static int[] quickSort(int[] data) {
return quickSort(data, 0, data.length - 1);
}
public static int[] quickSort(int[] data, int low, int height) {
int l = low;
int h = height;
int povit = data[l];
while (l < h) {
while (l < h && data[h] >= povit) h--;
if (l < h) {
data[l] = data[h];
l++;
}
while (l < h && data[l] <= povit) l++;
if (l < h) {
data[h] = data[l];
h--;
}
data[l] = povit;
}
if (l - 1 > low) quickSort(data, low, l - 1);
if (h + 1 < height) quickSort(data, h + 1, height);
return data;
}
冒泡排序
內存優先
public static int[] bubbleSort(int[] array) {
if (array == null || array.length <= 1) return array;
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[j] <= array[i]) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
return array;
}
插入排序
內存優先
首先位置1上的數和位置0上的數進行比較,如果位置1上的數大於位置0上的數,將位置0上的數向後移一位,將1插入到0位置,否則不處理。位置k上的數和之前的數依次進行比較,如果位置K上的數更大,將之前的數向後移位,最後將位置k上的數插入不滿足條件點,反之不處理。
public static int[] insertSort(int[] array) {
if (array == null || array.length <= 1)
return array;
int j;
for (int i = 1; i < array.length; i++) {
// 如果 後一個 小於 前一個,就向前繼續查找
if (array[i] < array[i - 1]) {
int temp = array[i];
// 如果 當前大於temp 就向後移動一位
for (j = i; (j > 0) && (array[j-1] > temp); j--) {
array[j] = array[j - 1];
}
array[j] = temp;
}
}
return array;
}
2、鍊表算法
判斷鍊表有環
思路:快慢指針
兩鍊表合併
思路:
1、鍊表 head 記錄初始鍊表,tempHead 記錄當前點的鍊表 2、輸入l1 與 l2 長度可能不一致 3、進位記錄 carry
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
ListNode head = new ListNode();
ListNode tempHead = head;
head.next = tempHead;
while (l1 != null || l2 != null) {
ListNode tempNode = new Listnode();
int l1val = l1 == null ? 0 : l1.val;
int l2val = l2 == null ? 0 : l2.val;
int result = l1val + l2val + carry;
carry = result / 10;
tempNode.val = result % 10;
tempHead.next = tempNode;
tempHead = tempHead.next;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
if (carry > 0) {
ListNode tail = new ListNode(carry);
tempHead.next = tail;
}
return head.next;
}
查找單鍊表中的倒數第k個結點
快慢指針
如何實現一個lru
前後結點
如何定位鍊表尾部前面的第k個節點,寫一下
雙指針
單鍊表的反轉
方式一:
public ListNode reverseList(ListNode head) {
if(head==null) return head;
if (head.next==null) return head;
ListNode lastNode = reverseList(head.next);
head.next.next = head;
head.next = null;
return lastNode;
}
方式二:
public ListNode reverseList(ListNode head) {
if (head == null) return head;
ListNode tempHead = new ListNode(0);
ListNode tempNext = tempHead.next;
while (head != null) {
ListNode curNext = head.next;
head.next = tempNext;
tempNext = head;
head = curNext;
}
return tempNext;
}
從尾到頭列印單鍊表
思路: 使用棧
合併兩個有序的單鍊表,合併之後的鍊表依然有序
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode prehead = new ListNode(-1);
ListNode prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
// 合併後 l1 和 l2 最多只有一個還未被合併完,我們直接將鍊表末尾指向未合併完的鍊表即可
prev.next = l1 == null ? l2 : l1;
return prehead.next;
}
3、二叉樹算法
每個結點類:
1 public class TreeNode{
2 private String data;//自己結點數據
3 private TreeNode leftChild;//左孩子
4 private TreeNode rightChild;//右孩子
5
6 public String getData() {
7 return data;
8 }
9
10 public void setData(String data) {
11 this.data = data;
12 }
13
14 public TreeNode(String data){
15 this.data = data;
16 this.leftChild = null;
17 this.rightChild = null;
18 }
19 }
很簡單,每個結點信息包含自己結點數據以及指向左右孩子的指針(為了方便,我這裡就叫指針了)。
二叉樹的創建
我們創建如下二叉樹:
代碼實現:
public class BinaryTree {
private TreeNode root = null;
public TreeNode getRoot() {
return root;
}
public BinaryTree(){
root = new TreeNode("A");
}
/**
* 構建二叉樹
* A
* B C
* D E F G
*/
public void createBinaryTree(){
TreeNode nodeB = new TreeNode("B");
TreeNode nodeC = new TreeNode("C");
TreeNode nodeD = new TreeNode("D");
TreeNode nodeE = new TreeNode("E");
TreeNode nodeF = new TreeNode("F");
TreeNode nodeG = new TreeNode("G");
root.leftChild = nodeB;
root.rightChild = nodeC;
nodeB.leftChild = nodeD;
nodeB.rightChild = nodeE;
nodeC.leftChild = nodeF;
nodeC.rightChild = nodeG;
}
。。。。。。。
}
創建BinaryTree的時候就已經創建根結點A,createBinaryTree()方法中創建其餘結點並且建立相應關係。
獲得二叉樹的高度
樹中節點的最大層次稱為樹的高度,因此獲得樹的高度需要遞歸獲取所有節點的高度,取最大值。
/**
* 求二叉樹的高度
* @author Administrator
*
*/
public int getHeight(){
return getHeight(root);
}
private int getHeight(TreeNode node) {
if(node == null){
return 0;
}else{
int i = getHeight(node.leftChild);
int j = getHeight(node.rightChild);
return (i<j)?j+1:i+1;
}
}
獲取二叉樹的結點數
獲取二叉樹結點總數,需要遍歷左右子樹然後相加
1 /**
2 * 獲取二叉樹的結點數
3 * @author Administrator
4 *
5 */
6 public int getSize(){
7 return getSize(root);
8 }
9
10 private int getSize(TreeNode node) {
11 if(node == null){
12 return 0;
13 }else{
14 return 1+getSize(node.leftChild)+getSize(node.rightChild);
15 }
16 }
二叉樹的遍歷
二叉樹遍歷分為前序遍歷,中序遍歷,後續遍歷,主要也是遞歸思想,下面直接給出代碼
/**
* 前序遍歷——疊代
* @author Administrator
*
*/
public void preOrder(TreeNode node){
if(node == null){
return;
}else{
System.out.println("preOrder data:"+node.getData());
preOrder(node.leftChild);
preOrder(node.rightChild);
}
}
/**
* 中序遍歷——疊代
* @author Administrator
*
*/
public void midOrder(TreeNode node){
if(node == null){
return;
}else{
midOrder(node.leftChild);
System.out.println("midOrder data:"+node.getData());
midOrder(node.rightChild);
}
}
/**
* 後序遍歷——疊代
* @author Administrator
*
*/
public void postOrder(TreeNode node){
if(node == null){
return;
}else{
postOrder(node.leftChild);
postOrder(node.rightChild);
System.out.println("postOrder data:"+node.getData());
}
}
獲取某一結點的父結點
獲取結點的父節點也是遞歸思想,先判斷當前節點左右孩子是否與給定節點信息相等,相等則當前結點即為給定結點的父節點,否則繼續遞歸左子樹,右子樹。
1 /**
2 * 查找某一結點的父結點
3 * @param data
4 * @return
5 */
6 public TreeNode getParent(String data){
7 //封裝為內部結點信息
8 TreeNode node = new TreeNode(data);
9 //
10 if (root == null || node.data.equals(root.data)){
11 //根結點為null或者要查找的結點就為根結點,則直接返回null,根結點沒有父結點
12 return null;
13 }
14 return getParent(root, node);//遞歸查找
15 }
16
17 public TreeNode getParent(TreeNode subTree, TreeNode node) {
18
19 if (null == subTree){//子樹為null,直接返回null
20 return null;
21 }
22 //判斷左或者右結點是否與給定結點相等,相等則此結點即為給定結點的父結點
23 if(subTree.leftChild.data.equals(node.data) || subTree.rightChild.data.equals(node.data)){
24 return subTree;
25 }
26 //以上都不符合,則遞歸查找
27 if (getParent(subTree.leftChild,node)!=null){//先查找左子樹,左子樹找不到查詢右子樹
28 return getParent(subTree.leftChild,node);
29 }else {
30 return getParent(subTree.rightChild,node);
31 }
32 }
以上就是Android常見的排序、鍊表、二叉樹算法面試題;當然不止這些比喻: 堆/棧/隊列 、 哈希 、遞歸/回溯 、 動態規劃 、 字符串 、 雙指針 、 貪心算法 、 模擬 等等。想要在面試中披荊斬棘獲取更好的offer,可以前往獲取《Android面試精選題》內容很全面大家可以放心刷題。offer必到手!
【私信:「手冊」獲取】《Android精選面試題庫》
總結
找崗位要注意的是: 找准自己的定位
- 比如你特別想去A公司,你現在公司是10K,
- 先找幾個BCDE公司練練手,薪酬談判的時候直接要高價,比如20K
- 如果對方想也沒想就拒絕了,說明自己現在還不夠格,下次面試要15試試
- 如果對方猶豫或者答應了,下次面試你就可以要20K 以此類推
目的就是找准市場給自己的定價,心裡有一個譜。先找到自己的定位,然後再談判。