大厂刷题(一)
注:题目和解答均来自互联网,侵删
题目1
给定一个有序数组arr,代表坐落在X轴上的点。给定一个正数K,代表绳子的长度。返回绳子最多压中几个点?即使绳子边缘处盖住点也算盖住
int arr[1,4,9,10,20,21]
length = 10
一、常规思路:穷举法。O(N^2)
- 双层for循环,遍历每个节点,判断两个节点之前包含的节点数。
- 代码思路:
i = 0 ,j = 0 ,中间变量temp(记录节点数)。j ++,temp ++,当arr[j] - arr[i] > length 时 i ++ ,temp = 0。
二、优化思路:贪心算法。O(Nlog(N))
- 假设有个长度为10的绳子,每次尾部都会落到节点上,那么长度能盖到的节点就是对应最多的点数量。贪心:绳子的末端没必要放到一个不存在的点的位置。判断绳子所在末尾点n,往前的10的长度,存在多少大于n-10的节点,有序数组的查找,可使用二分查找。
- 代码思路:
public static int maxPoint1(int[] arr, int L) {
int res = 1;
for (int i = 0; i < arr.length; i++) {
int nearest = nearestIndex(arr, i, arr[i] - L);
res = Math.max(res, i - nearest + 1);
}
return res;
}
public static int nearestIndex(int[] arr, int R, int value) {
int L = 0;
int index = R;
while (L <= R) {
int mid = L + ((R - L) >> 1);
if (arr[mid] >= value) {
index = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return index;
}
三、进阶思路。窗口算法。O(N)
- 设置两个指针,i,j,初始为0。尾指针向后移动,直到尾指针和头指针的差距大于10时,记录移动的次数。然后头指针向后移动,次数-1,同时尾指针继续向后移动,直到尾指针和头指针的差距大于10时。依次循环记录节点数,取最大。
- 代码思路:
-
- 代码思路:
public static int maxPoint2(int[] arr, int L) {
int left = 0; //头指针
int right = 0; //尾指针
int N = arr.length; //数组长度
int max = 0; //最大节点数
while (left < N) { //头指针小于数组长度
//尾指针小于数组长度,两个指针的差小于绳子的长度。
while (right < N && arr[right] - arr[left] <= L) {
right++;
}
//返回最大节点数
max = Math.max(max, right - (left++));
}
return max;
}
题目二
给定一个文件目录的路径,写一个函数统计这个目录下所有的文件数量并返回隐藏文件也算,但是文件夹不算
可以将其理解为一个树,如下如,矩形表示文件夹,椭圆表示文件。那么下面就是树的遍历一般分为深度优先和广度优先。
一、思路1:深度遍历
- 一般使用栈的方式处理深度优先算法。
- 将A放入栈中,判断A是否为文件夹,是则将A弹出,将A下面的文件或者文件夹全部放入栈中,那么栈中的数据为B,1,C。
- 判断C是否为判断C是否为文件夹,是则将C弹出并将C下面的文件或者文件夹全部放入栈中,那么栈中的数据为B,1,4,D。
- 判断D是否为判断D是否为文件夹,是则将D弹出并将D下面的文件或者文件夹全部放入栈中,那么栈中的数据为B,1,4,5,6。
- 依次判断栈中的数据,弹出栈是判断为文件则计数加1。
- 直到栈为空,返回计数。
public class Code02_CountFiles {
// 注意这个函数也会统计隐藏文件
public static int getFileNumber(String folderPath) {
File root = new File(folderPath);
if (!root.isDirectory() && !root.isFile()) {
return 0;
}
if (root.isFile()) {
return 1;
}
Stack<File> stack = new Stack<>();
stack.add(root);
int files = 0;
while (!stack.isEmpty()) {
File folder = stack.pop();
for (File next : folder.listFiles()) {
if (next.isFile()) {
files++;
}
if (next.isDirectory()) {
stack.push(next);
}
}
}
return files;
}
public static void main(String[] args) {
// 你可以自己更改目录
String path = "C:\";
System.out.println(getFileNumber(path));
}
}
二、思路2:广度遍历
- 一般使用队列的方式处理深度优先算法。
- 将A放入队列中,判断A是否为文件夹,是则将A弹出,将A下面的文件或者文件夹全部放入队列的末尾中,那么队列中的数据为才C,1,B。
- 判断B是否为判断B是否为文件夹,是则将B弹出并将B下面的文件或者文件夹全部放入队列中,那么栈中的数据为3,2,C,1。
- 判断D是否为判断1是否为文件夹,是则将1弹出并将1下面的文件或者文件夹全部放入栈中,那么栈中的数据为3,2,C。
- 依次判断队列中的数据,弹出队列是判断为文件则计数加1。
- 直到队列为空,返回计数。
题目三
一个数组中只有两种字符’G’和’B’,想让所有的G都放在左侧,所有的B都放在右侧但是只能在相邻字符之间进行交换操作,返回至少需要交换几次
如:GBGBGBGBGB
思路:贪心算法
假设G需要在B的左边,那么第一个出现G应该放到第一个位置,第二个出现的G应该放到第二个位置,依次类推。
public static int minSteps2(String s) {
if (s == null || s.equals("")) {
return 0;
}
char[] str = s.toCharArray();
int step1 = 0;
int gi = 0;
for (int i = 0; i < str.length; i++) {
if (str[i] == 'G') { // 当前的G,去左边 方案1
step1 += i - (gi++);
}
}
return step1;
}