每日算法&面试题,大厂特训十四天——第三天(双指针)

253 阅读4分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

导读

在这里插入图片描述

肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进行十四天的一个小总结。还在等什么快来一起肥学进行十四天挑战吧!!

算法特训十四天

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length, left = 0, right = 0;
        while (right < n) {
            if (nums[right] != 0) {
                swap(nums, left, right);
                left++;
            }
            right++;
        }
    }

    public void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

 
示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:27 之和等于目标数 9 。因此 index1 = 1, index2 = 2
示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
//初始时两个指针分别指向第一个元素位置和最后一个元素的位置。每次计算两个指针指向的两个元素之和,并和目标值比较。如果两个元素之和等于目标值,则发现了唯一解。如果两个元素之和小于目标值,则将左侧指针右移一位。如果两个元素之和大于目标值,则将右侧指针左移一位。移动指针之后,重复上述操作,直到找到答案。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int low = 0, high = numbers.length - 1;
        while (low < high) {
            int sum = numbers[low] + numbers[high];
            if (sum == target) {
                return new int[]{low + 1, high + 1};
            } else if (sum < target) {
                ++low;
            } else {
                --high;
            }
        }
        return new int[]{-1, -1};
    }
}

面试题

ConcurrentHashMap 的存储结构是怎样的? Java7 中 ConcurrnetHashMap 使用的分段锁,也就是每一个 Segment 上同时只有一 个线程可以操作,每一个 Segment 都是一个类似 HashMap 数组的结构,它可以扩容, 它的冲突会转化为链表。但是 Segment 的个数一但初始化就不能改变,默认 Segment 的个数是 16 个。  Java8 中的 ConcurrnetHashMap 使用的 Synchronized 锁加 CAS 的机制。结构也由 Java7 中的 Segment 数组+HashEntry 数组 + 链表 进化成了 Node 数组 + 链表 / 红 黑树,Node 是类似于一个 HashEntry 的结构。它的冲突再达到一定大小时会转化成红 黑树,在冲突小于一定数量时又退回链表。

线程池大小如何设置? CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N (CPU核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断, 或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态, 而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。 I/O 密集型任务(2N):这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线 程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU交出给其它线程使 用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。 如何判断是 CPU 密集任务还是 IO 密集任务? CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。 单凡涉及到网络读取,文件读取这类都是 IO 密集型,这类任务的特点是 CPU 计算耗费时间 相比于等待 IO操作完成的时间来说很少,大部分时间都花在了等待 IO 操作完成上