一位比我大两届的大哥(坐我的对面的侧边)看着我说:没事学习一下,顺便搞个项目出来。我真的会笑,问他怎么知道我没事干,他说没集中精神,我在看着算法题目,在分析,他说我没有集中精神,真厉害,哈哈哈。
Day4:剑指 Offer 11. 旋转数组的最小数字
其实刚开始写题的时候真的会很懵,会揪着题干不放,但是你从他给的例子去分析又是另一种想法了,多做你才能领会到其中的奥秘,其实最主要的还是要把题给解出来,而不是题目花里胡哨说了一堆,你要揪着哪一方面去实现。
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
题解:双指针解法,数组升序排列,由列子:numbers = [3,4,5,1,2]可以看出,是由中间值往后往前的两个升序有序数组,前边的的数组与后边的数组升序排列,使用双指针的写法,一开始循环就判断左指针如果小于右指针直接返回(这是关键,最小值总是最左边的数),其他都是指针移动,若中间值大于最右边的值,l=mid+1(最小值在右边),若中间值小于最右边的值,r=mid(最小值再右边),相等的时候向右移动一位
一开始:numbers[l]<numbers[r],第一个数组的最小值,小于第二个数组最大值(不存在此类情况)
循环开始:取中间值,
class Solution {
public int minArray(int[] numbers) {
int l=0;
int r=numbers.length-1;
while(l<r){
if(numbers[l]<numbers[r]){
return numbers[l];
}
int middle = (l+r)/2;
if(numbers[l]>numbers[middle]){//第一个数组只有一个值的时候
r=middle;
}else if(numbers[l]<numbers[middle]){//移动到第二个数组
l=middle+1;
}else{ //相等的时候直接移动
l++;
}
}
return numbers[l];
}
}
Day4:剑指 Offer 12. 矩阵中的路径
力扣链接:剑指 Offer 12. 矩阵中的路径
题目:给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
题解:遍历的方式,找到第一个字母所在的位置,从此位置开始向四周开始检索,回溯遍历,每次遍历之后都需要记录一下(用一个特殊字符记录一下),如果为FALSE则重新遍历,再次寻找第一个字母,返回true,则继续查找,直到找到完整的顺序的单词结束。
class Solution {
int n;
int m;
int len;
public boolean exist(char[][] board, String word) {
n = board.length;
m= board[0].length;
len = word.length();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
//判断第一个字母位置,从第一个字母位置开始进行搜索
if(cheakWordAt(board,i,j,word,0)){
return true;
}
}
}
return false;
}
boolean cheakWordAt(char[][] board,int i ,int j,String word ,int k ){
//判断字母是否相同
if(i<0 || i>=n || j<0 || j>=m || board[i][j]!=word.charAt(k)){
return false;
}
if(k==len-1){
return true;
}
//遍历过的做一个标记
board[i][j] = '\n';
//搜索四周
boolean flag = cheakWordAt(board,i,j+1,word,k+1) || cheakWordAt(board,i+1,j,word,k+1)
||cheakWordAt(board,i-1,j,word,k+1) || cheakWordAt(board,i,j-1,word,k+1);
board[i][j] = word.charAt(k);
return flag;
}
}
Day4:面试题13. 机器人的运动范围
力扣链接:面试题13. 机器人的运动范围
这几道题都需要先了解一下,深度优先搜索跟广度优先搜索。
题目:地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
题解:使用深度优先搜索(Depth First Search,DFS)方法进行求解。根据官方的解释可以看到,随着k的增大,只是从上往下扩大了机器人可以走的范围,所以我们只需要从坐标(0,0)开始往下遍历累计,同时需要计算k与坐标的关系,遇到非法位置的不累计,直到遍历到坐标(m,n)。当碰到边界或者是障碍格子的时候结束此次遍历,直接return达到结束遍历的效果。
class Solution {
int m;
int n;
int k;
boolean[][] visited;
public int movingCount(int m, int n, int k) {
this.m = m;
this.n = n;
this.k = k;
visited = new boolean[m][n];
return dfs(0, 0);
}
int dfs(int i, int j) {
if (i < 0 || j < 0 ||i>=m||j>=n|| visited[i][j] || k < Cumulative(i) + Cumulative(j)) {
return 0;
}
visited[i][j] = true;
return 1 + dfs(i, j + 1) + dfs(i + 1, j);
}
int Cumulative(int x) {
int res = 0;
while(x!=0){
res = res+x%10;
x=x/10;
}
return res;
}
}
end》》》
当你懂得拒绝“廉价”的优越感的时候,你就已经进步了