示例:
WordsFrequency wordsFrequency = new WordsFrequency({“i”, “have”, “an”, “apple”, “he”, “have”, “a”, “pen”});
wordsFrequency.get(“you”); //返回0,"you"没有出现过
wordsFrequency.get(“have”); //返回2,"have"出现2次
wordsFrequency.get(“an”); //返回1
wordsFrequency.get(“apple”); //返回1
wordsFrequency.get(“pen”); //返回1
提示:
book[i]中只包含小写字母
1 <= book.length <= 100000
1 <= book[i].length <= 10
get函数的调用次数不会超过100000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/words-frequency-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Map<String , Integer> map = new HashMap<>();
public WordsFrequency(String[] book) {
for(String s:book){
map.put(s, map.getOrDefault(s, 0)+1);
}
}
public int get(String word) {
if(!map.containsKey(word)) return 0;
return map.get(word);
}
Q16.3 交点
给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
示例 1:
输入:
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
输出: {0.5, 0}
示例 2:
输入:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出: {1, 1}
示例 3:
输入:
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
输出: {},两条线段没有交点
提示:
坐标绝对值不会超过 2^7
输入的坐标均是有效的二维坐标
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public double[] intersection(int[] start1, int[] end1, int[] start2, int[] end2) {
//求两线段的最大点和最小点
int xmin1 = start1[0] < end1[0] ? start1[0] : end1[0];
int ymin1 = start1[1] < end1[1] ? start1[1] : end1[1];
int xmin2 = start2[0] < end2[0] ? start2[0] : end2[0];
int ymin2 = start2[1] < end2[1] ? start2[1] : end2[1];
int xmax1 = start1[0] > end1[0] ? start1[0] : end1[0];
int ymax1 = start1[1] > end1[1] ? start1[1] : end1[1];
int xmax2 = start2[0] > end2[0] ? start2[0] : end2[0];
int ymax2 = start2[1] > end2[1] ? start2[1] : end2[1];
double x = 0;
double y = 0;
//如果两点在直线的同一侧,代入方程同号
int f11 = fangcheng(start2[0],start2[1],start1[0],start1[1],end1[0],end1[1]);
int f12 = fangcheng(end2[0],end2[1],start1[0],start1[1],end1[0],end1[1]);
int f21 = fangcheng(start1[0],start1[1],start2[0],start2[1],end2[0],end2[1]);
int f22 = fangcheng(end1[0],end1[1],start2[0],start2[1],end2[0],end2[1]);
//两点在直线的同侧,没有交点
if (f11 * f12 > 0 || f21*f22 > 0){
return new double[0];
}else if(f11 == f12 && f12 == f21 && f21 == f22){//四点共线
// 没有交叉排列
if (xmax1 < xmin2 || xmax2 < xmin1){
return new double[0];
}else if(xmax1 == xmin1 && xmin1 == xmax2 && xmax2 == xmin2){//垂直的线,判断y
//没有交叉
if (ymax1 < ymin2 || ymax2 < ymin1){
return new double[0];
}else{
//取两个条线的小值中最大的,得交叉点小点
x = xmax1;
y = ymin1 > ymin2 ? ymin1 : ymin2;
return new double[]{x,y};
}
}else {
//取两个条线的小值中最大的,得交叉点小点
x = xmin1 > xmin2 ? xmin1 : xmin2;
if (start1[0] == x){
y = start1[1];
}else if(end1[0] == x){
y = end1[1];
}else if (start2[0] == x){
y = start2[1];
}else {
y = end2[1];
}
return new double[]{x,y};
}
}else{
// 线段1垂直
if (start1[0] == end1[0]){
x = start1[0];
double xue2 = 1.0*(start2[1] - end2[1])/(start2[0] - end2[0]);
double b2 = end2[1] - xue2 * end2[0];
y = xue2 * x + b2;
return new double[]{x,y};
}else if (start2[0] == end2[0]){//线段2垂直
x = start2[0];
double xue1 = 1.0*(start1[1] - end1[1])/(start1[0] - end1[0]);
double b1 = end1[1] - xue1 * end2[0];
y = xue1 * x + b1;
return new double[]{x,y};
}else {//通用情况,线段1和线段2都不垂直,计算斜率、常量值,y=a*x+b
double xue1 = 1.0*(start1[1] - end1[1])/(start1[0] - end1[0]);//斜率1
double xue2 = 1.0*(start2[1] - end2[1])/(start2[0] - end2[0]);//斜率2
double b1 = end1[1] - xue1 * end1[0];//常量b1
double b2 = end2[1] - xue2 * end2[0];//常量b2
x = (b2 - b1)/(xue1 - xue2);
y = xue1 * x + b1;
return new double[]{x,y};
}
}
}
//验证两点是否在另一条直线的同一侧,同一侧同号,不同侧异号
private int fangcheng(int x,int y,int x0,int y0,int x1,int y1){
return (x-x0)(y1-y0) - (x1-x0)(y-y0);
}
}
Q16.4 井字游戏
设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ",“X"和"O"组成,其中字符” "代表一个空位。
以下是井字游戏的规则:
玩家轮流将字符放入空位(" ")中。
第一个玩家总是放字符"O",且第二个玩家总是放字符"X"。
"X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
当所有位置非空时,也算为游戏结束。
如果游戏结束,玩家不允许再放置字符。
如果游戏存在获胜者,就返回该游戏的获胜者使用的字符(“X"或"O”);如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。
示例 1:
输入: board = [“O X”," XO",“X O”]
输出: “X”
示例 2:
输入: board = [“OOX”,“XXO”,“OXO”]
输出: “Draw”
解释: 没有玩家获胜且不存在空位
示例 3:
输入: board = [“OOX”,“XXO”,"OX "]
输出: “Pending”
解释: 没有玩家获胜且仍存在空位
提示:
1 <= board.length == board[i].length <= 100
输入一定遵循井字棋规则
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/tic-tac-toe-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
// 井字游戏
public String tictactoe(String[] board) {
int n = board.length;
char[][] grid = new char[n][n];
for (int i = 0; i < n; i++) {
grid[i] = board[i].toCharArray();
}
int empty = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == ’ ') empty++;
}
}
if (empty > 0) {
if (check(grid, ‘X’)) return “X”;
if (check(grid, ‘O’)) return “O”;
return “Pending”;
}
if (check(grid, ‘X’)) return “X”;
if (check(grid, ‘O’)) return “O”;
return “Draw”;
}
private boolean check(char[][] grid, char c) {
int n = grid.length;
// 检查行
for (int row = 0; row < n; row++) {
int col;
for (col = 0; col < n; col++) {
if (grid[row][col] != c) break;
}
if (col >= n) return true;
}
// 检查列
for (int col = 0; col < n; col++) {
int row;
for (row = 0; row < n; row++) {
if (grid[row][col] != c) break;
}
if (row >= n) return true;
}
// 主对角线
int i;
for (i = 0; i < n; i++) {
if (grid[i][i] != c) break;
}
if (i >= n) return true;
// 副对角线
i = 0;
for (; i < n; i++) {
if (grid[i][n - 1 - i] != c) break;
}
return i >= n;
}
}
Q16.5 阶乘尾数
设计一个算法,算出 n 阶乘有多少个尾随零。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/factorial-zeros-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public int trailingZeroes(int n) {
/*
0 是由 *10 得到的,而 10 是由 2 * 5 得到的
因此我们求 n! 过程中存在多少个 2 * 5
因为 2 的个数必定比 5 的个数多,因此我们只求 5 的个数
如果直接一个一个遍历,即
for(int i = 5; i <= n; i++){
int temp = i;
while(temp % 5 == 0){
count++;
temp /= 5;
}
}
那么 n 过大时,从 1 遍历到 n, 那么会超时,因此我们修改下规律
n! = 1 * 2 * 3 * 4 * (1 * 5) * … * (2 * 5) * … * (3 * 5) …
我们发现,
每隔 5 个数就会出现 一个 5,因此我们只需要通过 n / 5 来计算存在存在多少个 5 个数,那么就对应的存在多少个 5
但是,我们也会发现
每隔 25 个数会出现 一个 25, 而 25 存在 两个 5,我们上面只计算了 25 的一个 5,因此我们需要 n / 25 来计算存在多少个 25,加上它遗漏的 5
同时,我们还会发现
每隔 125 个数会出现一个 125,而 125 存在 三个 5,我们上面只计算了 125 的两个 5,因此我们需要 n / 125 来计算存在多少个 125,加上它遗漏的 5
…
因此我们 count = n / 5 + n / 25 + n / 125 + …
最终分母可能过大溢出,上面的式子可以进行转换
count = n / 5 + n / 5 / 5 + n / 5 / 5 / 5 + …
因此,我们这样进行循环
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
如何做好面试突击,规划学习方向?
面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。
学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。
我们搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-cjuOQnxr-1711658034641)]
如何做好面试突击,规划学习方向?
面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。
学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。
我们搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
[外链图片转存中…(img-3N9dNhyd-1711658034642)]
我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多