面试题随记

刚经历某互联网公司第一轮面试,面试题为三道编程题,三十分钟内完成,完成两道,剩余一道由于时间不够所以就写出了思路,在这里做一个记录。具体算法思想见代码注解。

数组操作,求:交集、并集、差集

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;
        }
    }
}

版权声明:本文为mrxiaobai-wen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/mrxiaobai-wen/p/14968534.html