剛經歷某網際網路公司第一輪面試,面試題為三道程式設計題,三十分鐘內完成,完成兩道,剩餘一道由於時間不夠所以就寫出了思路,在這裡做一個記錄。具體演算法思想見程式碼註解。
陣列操作,求:交集、並集、差集
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* 陣列操作,求:交集、並集、差集
*
* 在能夠表達演算法思想的前提下儘量簡化一下情況,所以這裡就假定陣列內元素不重複
*/
public class ArrayOperation {
@Test
public void test() {
int[] arr1 = new int[]{1,3,6,9,8};
int[] arr2 = new int[]{1,3,6,11,10};
// 排序測試
sort(arr1,0,arr1.length - 1);
sort(arr2,0,arr2.length - 1);
// 交集
List<Integer> intersectionResult = intersection(arr1,arr2);
// 並集
List<Integer> unionResult = union(arr1,arr2);
// 差集
List<Integer> differenceResult = difference(arr1,arr2);
}
/**
* 快排
*
* 思路:挖坑填數+分治法
*/
private void sort(int[] arr,int low,int high) {
if (low >= high) {
return;
}
int left = low,right = high;
int movedVal = arr[left];
while (left < right) {
while (left < right && arr[right] >= movedVal) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= movedVal) {
left++;
}
arr[right] = arr[left];
}
arr[left] = movedVal;
sort(arr,low,left - 1);
sort(arr,left + 1,high);
}
/**
* 交集
*
* 思路:將兩個有序陣列遍歷,相等則加入結果中,不等較小值的陣列索引加1,直到任意一個陣列遍歷完成
*/
private List<Integer> intersection(int[] arr1,int[] arr2) {
sort(arr1,0,arr1.length - 1);
sort(arr2,0,arr2.length - 1);
List<Integer> result = new ArrayList<>();
int index1 = 0,index2 = 0;
int len1 = arr1.length,len2 = arr2.length;
while (index1 < len1 && index2 < len2) {
if (arr1[index1] == arr2[index2]) {
result.add(arr1[index1]);
index1++;
index2++;
} else if (arr1[index1] > arr2[index2]) {
index2++;
} else {
index1++;
}
}
return result;
}
/**
* 並集
*
* 思路:依次遍歷兩個陣列,相等索引資料加入到結果中一次,兩個索引同時加1,不相等的將較小值加入結果同時索引加1;當任意一個陣列遍歷完後,將另一個陣列剩餘元素新增進結果;
*/
private List<Integer> union(int[] arr1,int[] arr2) {
int len1 = arr1.length,len2 = arr2.length;
sort(arr1,0,len1 - 1);
sort(arr2,0,len2 - 1);
int index1 = 0,index2 = 0;
List<Integer> result = new ArrayList<>();
while (index1 < len1 && index2 < len2) {
if (arr1[index1] == arr2[index2]) {
result.add(arr1[index1]);
index1++;
index2++;
} else if (arr1[index1] > arr2[index2]) {
result.add(arr2[index2]);
index2++;
} else {
result.add(arr1[index1]);
index1++;
}
}
while (index1 < len1) {
result.add(arr1[index1]);
index1++;
}
while (index2 < len2) {
result.add(arr2[index2]);
index2++;
}
return result;
}
/**
* 差集
*
* 思路:依次遍歷兩個陣列,值相等索引同時加1忽略相同值;不同值加入較小值並將索引加1,直到任意一個陣列遍歷完成;然後將另一個素組中剩餘元素加進結果中。
*/
private List<Integer> difference(int[] arr1,int[] arr2) {
int len1 = arr1.length,len2 = arr2.length;
int index1 = 0,index2 = 0;
List<Integer> result = new ArrayList<>();
while (index1 < len1 && index2 < len2) {
if (arr1[index1] == arr2[index2]) {
index1++;
index2++;
} else if (arr1[index1] > arr2[index2]) {
result.add(arr2[index2]);
index2++;
} else {
result.add(arr1[index1]);
index1++;
}
}
while (index1 < len1) {
result.add(arr1[index1]);
index1++;
}
while (index2 < len2) {
result.add(arr2[index2]);
index2++;
}
return result;
}
}
求一個陣列中的連續子列表的最大和
import org.junit.Test;
/**
* 求一個陣列中的連續子列表的最大和
*/
public class SubListSum {
@Test
public void test() {
int[] arr = new int[]{1,2,3,6,7,8,5,6};
// 測試結果 21
int sum = subListSum(arr);
}
/**
* 思路:使用動態規劃
* 初始dp[0] = arr[0]
* 如果arr[i] = arr[i - 1],則dp[i] = dp[i - 1] + arr[i]
* 否則dp[i] = arr[i]
*/
private int subListSum(int[] arr) {
int[] dp = new int[arr.length];
dp[0] = arr[0];
int sum = dp[0];
for (int i = 1;i < arr.length;i++) {
if (arr[i] == arr[i - 1] + 1) {
dp[i] = dp[i - 1] + arr[i];
} else {
dp[i] = arr[i];
}
sum = Math.max(sum,dp[i]);
}
return sum;
}
}
求元素首次出現下標
import java.util.ArrayList;
import java.util.List;
/**
* 一個可能多次重複元素的陣列,然後找出給定值首次出現的下標,如果未出現返回-1
*/
public class FirstSubscript {
/**
* 整體思路:將元素和對應下標組成一對,不斷的插入一個列表中生成一個有序列表,然後查詢的時候使用二分查詢
*
* 進階思路:將元素和對應小標組成一對,維護一個紅黑樹,使用紅黑樹進行插入和查詢
*/
public static void main(String[] args) {
int[] arr = new int[]{1,1,2,1,2,2,7,8,9,9,8,7};
FirstSubscript fs = new FirstSubscript(arr);
// 7首次出現下標 6
int result1 = fs.queryFirstIndex(7);
// 20未出現 -1
int result = fs.queryFirstIndex(20);
}
private List<Entry> list = new ArrayList<>();
public FirstSubscript(int[] arr) {
for (int i = 0;i < arr.length;i++) {
int val = arr[i];
int li = 0;
while (li < list.size() && list.get(li).val < val) {
li++;
}
if (li >= list.size() || list.get(li).val != val) {
if (li >= list.size()) {
list.add(new Entry(val,i));
} else {
list.set(li,new Entry(val,i));
}
}
}
}
/**
* list進行二分查詢
*/
private int queryFirstIndex(int val) {
int left = 0,right = list.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
int tempVal = list.get(mid).val;
if (tempVal == val) {
return list.get(mid).index;
} else if (tempVal > val) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
private class Entry {
int val;
int index;
Entry(int val,int index) {
this.val = val;
this.index = index;
}
}
}