面试笔试算法 - haizeiOJ

这篇博客主要涵盖了面试中常见的算法题目,包括简单题如丑数、排序问题,以及二分查找、模拟、贪心、枚举、STL、递归深度搜索、广度搜索和并查集等算法的实例解析。通过这些题目,帮助读者提升解决算法问题的能力。
摘要由CSDN通过智能技术生成

目录

简单题

70 丑数,记录值

// 通过空间存储下标更新经 2 3 5 倍乘后的下标
a[0] = 1;
int i2 = 0, i3 = 0, i5 = 0;
int m2 = a[i2] * 2;
int m3 = a[i3] * 3;
int m5 = a[i5] * 5;
mmin = min(m2, min(m3, m5));
if (mmin == m2) i2++;
if (mmin == m3) i3++;
if (mmin == m5) i5++;

二分

380 sort 排序

381 sort 排序

386 朴素二分 直接查找元素

387 找西瓜,尽可能小,0011 问题,查找第一个 1

while (l != r) {
   
	int mid = (l + r) / 2;
	if (wm[mid].num >= target) {
   
		r = mid; // 右边可能
	} else {
   
		l = mid + 1; // 左边肯定不是
	}
}
// 输出 l r 位置均可

390 原木切割,尽可能大, 1100 问题

// func 通过计算以改长度切割是否满足段数要求
int l = 1, r = lr; // 确定左右边界,1 - 最短原木长
while (l != r) {
   
	int mid = (l + r + 1) / 2;
	// 原木切割数量足够
	if (func(mid) >= m) {
   
		l = mid; // 左边可能
	} else {
   
		r = mid - 1; // 右边拒绝
	}
}
// return l r 均可

393 切绳子,尽可能长,1100 问题

// func 通过计算以改长度切割是否满足段数要求
double l = 0, r = lr; // 确定左右
// 小数通过精度判断
while (l - r > 0.00001) {
   
	double mid = (l + r + 1) / 2;
	if (func(mid) >= m) {
   
		l = mid;
	} else {
   
		r = mid - 1;
	}
}

82 伐木,据木材但尽可能多,1100 问题

// func 通过计算以改长度切割是否满足段数要求
int l = 0, r = tr; // 确定左右,右点选最长的
while (l != r) {
   
	int mid = (l + r + 1) / 2;
	if (func(mid) >= m) {
   
		l = mid;
	} else {
   
		r = mid - 1;
	}
}

391 数列分段,和尽可能小,0011 问题

// func 计算是否符合分段数
int func(int x) {
   
	int cnt = 0, now = 0;
	for (...) {
   
		// 分段和计数逻辑
		if (now + num[i] == x) {
   
			cnt++;
			now = 0;
		} else if (now + num[i] > x) {
   
			cnt++;
			now = num[i];
		} else {
   
			now += num[i];
		}
	}
	if (now) cnt++;
	return cnt;
}
int l = tl, r = tr; // 左为单最大元素,右为元素和
while (l != r) {
   
	int mid = (l + r) / 2;
	if (func(mid) >= m) {
   
		r = mid;
	} else {
   
		l = mid + 1;
	}
}
...

394 跳石头,最近的尽可能远,1100 问题

// func 输入间距确认移走石头数
int func(int d) {
   
	int cnt = 0, last = 0;
	for (...) {
   
		// 小于最小间距的石头要移走
		if (num[i] - last < d) {
   
			cnt++;
		} else {
   
			last = num[i];
		}
	}
	return cnt;
}

int l = tl, r = ll; // 左为最小的间距,右为起始石头到结束石头的间距
while (l != r) {
   
	int mid = (l + r + 1) / 2;
	if (func(mid) <= m) {
   
		l = mid;
	} else {
   
		r = mid - 1;
	}
}
...

392 丢瓶盖,最近的尽可能远,1100 问题

// func 根据距离返回丢瓶盖书
int func(int d) {
   
	int s = 0, last = num[0];
	for (...) {
   
		if (last - num[i] >= d) {
   
			s++;
			last = num[i];
		}
	}
	return s;
}

int l = 1, r = tr; // 距离为从 1 到最大坐标
while (l != r) {
   
	int mid = (l + r + 1) / 2;
	if (func(mid) >= m) {
   
		l = mid;
	} else {
   
		r = mid - 1;
	}
}

395 复制书稿,时间尽可能短,0011 问题

// func 根据时间返回抄写书稿的人数
int func(int x) {
   
    int cnt = 0, now = 0;
    for (int i = 0; i < m; ++i) {
   
        if (now + num[i] == x) {
   
            cnt++;
            now = 0;
        } else if (now + num[i] > x) {
   
            cnt++;
            now = num[i];
        } else {
   
            now += num[i];
        }
    }
    if (now) {
   
        cnt++;
    }
    return cnt;
}
int l = tl, r = tr; // 左为最长抄书人的时间,右为抄书总时间
while (l != r) {
   
	int mid = (l + r) / 2;
	if (func(mid) <= k) [
		r = mid;
	} else {
   
		l = mid + 1;
	}
}
...

244 正方形围栏大小,满足条件最小的,0011 问题

// 在 l r 范围内查找,找到一个长度正好符合 x 方向和 y 方向上的围栏条件

// 在选好的 x 轴后的 y 轴上判定数量
bool check_y(int s, int e, int l) {
   
	int cnt = 0;
	for (int i = s; i <= e; ++i) {
   
		tmp[cnt++] = arr[i].y;
	}
	sort(tmp, tmp + cnt);
	// 满足数量大于等于 c
	for (int i = c - 1; i < cnt; ++i) {
   
		if (tmp[i] - tmp[i - c + 1] < l) return 1;
	}
	return 0;
}

// 先看 x 轴上在该长度是否满足数量要求,再看 y 轴,都满足符合要求
bool check(int l) {
   
	int j = 0;
	for (int i = 0; i < n; ++i) {
   
		while (arr[i].x - arr[j].x >= l) ++j;
		if (i - j + 1 < c) return 0;
		while (check_y(j, i)) return 1;
	}
	return 0;
}

int bs(int l, int r) {
   
	if (l == r) return l;
	int mid = (l + r) / 2;
	// 如果该长度正方形满足容纳,正方形可以再小,直到找到一个可以满足最小的容纳
	if (check(mid)) return bs(l, mid);
	// 不满足容纳,可以再大
	return bs(mid + 1, r);
}

模拟

599 两数之和,左右指针

while (l < r) {
   
	if (num[l] + num[r] == t) // 输出结果
	else if (num[l] + num[r] < t) l++;
	else r--;
}

600 杨氏矩阵,左右指针

// 特殊考虑,左下角为起点,上边的小,右边的大
while (1) {
   
	if (num[x][y] == t) // 输出结果
	else if (num[x][y] > t) x--;
	else y++;
}

477 模拟

479 模拟

// 满足分制还有分差才结束一句
// 通过 a[ind][2] ind 为局数,两个双方分值,后输出

480 模拟

// 读懂题意,设置状态方便计数
struct node {
   
	char s[4]; // 击球情况
	int num1; // 每轮第一次击球得分
	int num2; // 每轮第二次共击球得分
	int flag; // 每轮状态 2 一次全击中, 1 二次全击中,0 二次没击完
}
...
ans += b[i].num2;
if (b[i].flag == 1) {
   
	ans += b[i + 1].num1;
} else if (b[i].flag == 2) {
   
	if (b[i + 1].flag == 2) {
   
		ans += 10 + b[i + 2].num1;
	} else {
   
		ans += b[i + 1].num2;
	}
}
...

481 模拟

// 模拟,使用 ans[ind][2] ind 指示局数, 2 指示双方得分,方便计数输出

484 表输出模拟

// 读入字符串
while (cin >> str) {
   
	for (int i = 0; str[i]; ++i) {
   
		num[str[i]]++;
	}
}
// 找出最多出现字符数 mmax 为屏幕高度输出

485 模拟

// 确认均值然后把所有点分配均值即可
if (num[i] != avg) {
   
	num[i + 1] += num[i] - avg;
	num[i] = avg;
}

478 模拟

// 确认方向数组和退出条件即可

526 模拟,字符替换

// 按题意检查函数
int check(string str) {
   
    int flag_at = 0;
    if (str[0] == '.' || str[str.size() - 1] == '.') return 0;
    for (int i = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值