面试题随记一
刚经历某互联网公司第一轮面试,面试题为三道编程题,三十分钟内完成,完成两道,剩余一道由于时间不够所以就写出了思路,在这里做一个记录。具体算法思想见代码注解。
数组操作,求:交集、并集、差集
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;
}
}
}