71.简化路径
该题目就是使用了一个双向队列进行操作,没有什么难度
public String simplifyPath(String path) {
String[] change = path.split("/");
Deque<String> deque = new LinkedList<>();
for(int i=0; i<change.length; i++) {
if(change[i].equals("")) {
continue;
}
//当前目录不用管
if(change[i].equals(".")) {
continue;
}
//返回上一层目录
if(change[i].equals("..")) {
//已经是根目录
if(deque.size() == 0) {
continue;
}
deque.removeLast();
continue;
}
//说明是目录,入队
deque.addLast(change[i]);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("/");
while(deque.size() != 0) {
stringBuilder.append(deque.poll() + "/");
}
return stringBuilder.length() == 1 ? stringBuilder.toString() : stringBuilder.substring(0,stringBuilder.length()-1);
}
73.矩阵置零
该题目的思路就是使用两个set集合保存原矩阵为0的行列,之后我们再次对矩阵进行遍历,如果矩阵对应行列有一个在set中则置0。
public void setZeroes(int[][] matrix) {
//记录是否被访问过
Set<Integer> rows = new HashSet<>();
Set<Integer> cols = new HashSet<>();
int row = matrix.length;
int col = matrix[0].length;
for(int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
if(matrix[i][j] == 0) {
//标记其行列
rows.add(i);
cols.add(j);
}
}
}
for(int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
if(rows.contains(i) || cols.contains(j)) {
matrix[i][j] = 0;
}
}
}
}
74.搜索二维矩阵
该二位矩阵有两个特点:
1.每行有序
2.该行第一位 > 上一行的第一位
我们可以根据这两个条件进行搜索,时间复杂度o(m + n),也可以使用二分查找的方法提高效率
//搜索二维矩阵
public boolean searchMatrix(int[][] matrix, int target) {
if(matrix.length == 0) {
return false;
}
if(matrix[0].length == 0) {
return false;
}
//按第一行搜索
int i;
for(i=0; i<matrix.length; i++) {
if(matrix[i][0] == target) {
return true;
}
if(matrix[i][0] > target) {
break;
}
}
//找出对应行
int row = i - 1;
//第一行就没满足
if(row < 0) {
return false;
}
for(int col=0; col<matrix[0].length; col++) {
if(matrix[row][col] == target) {
return true;
}
}
return false;
}
75.颜色分类
该题主要使用双指针法,一个标记红色放置点,一个标记白色放置点。
针对这两个指针的位置有一定限制
红色指针一定是 <= 白色指针,因为红色指针代表 0 的位置,必须放在排序后的前方,所以不能够被修改,而白色的位置可能到后面可能会被 0 替换掉。
在循环中我们碰到 1 时候就会跟白色的放置点进行替换,并且向后移动放置点(此时白色指针和红色指针就会开始分离)
//颜色分类
public void sortColors(int[] nums) {
int white = 0;
int red = 0;
for(int i=0; i<nums.length; i++) {
//碰到红色 0 ,需要移动到前面
if(nums[i] == 0) {
swap(nums,red,i);
//说明我们把 1 置换了
if(red < white) {
swap(nums,white,i);
}
white++;
red++;
continue;
}
if(nums[i] == 1) {
swap(nums,white++,i);
}
}
}
public void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
77.组合
经典回溯
//组合
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> lists = new ArrayList<>();
backTrace(lists,new ArrayList<>(),k,n,1);
return lists;
}
public void backTrace(List<List<Integer>> lists, List<Integer> list, int k, int n, int index) {
if(list.size() == k) {
lists.add(new ArrayList<>(list));
return;
}
if(index > n){
return;
}
for(int i=index; i<=n; i++) {
list.add(i);
backTrace(lists, list, k, n, i + 1);
list.remove(list.size() - 1);
}
}
78.子集
也是经典回溯
//子集
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
backTrace(lists,new ArrayList<>(),nums,0);
//添加空集
lists.add(new ArrayList<>());
return lists;
}
public void backTrace(List<List<Integer>> lists, List<Integer> list, int[] nums, int index) {
for(int i=index; i<nums.length; i++) {
list.add(nums[i]);
lists.add(new ArrayList<>(list));
backTrace(lists, list, nums, i + 1);
list.remove(list.size() - 1);
}
}
79.单词搜索
使用的是深度优先算法,我们该题搜索路径很多,上下左右都可以,但是需要避免重复访问(使用一个数组对方问的路途进行保存)
public boolean exist(char[][] board, String word) {
int row = board.length;
int col = board[0].length;
for(int i=0; i<row; i++) {
for(int j=0; j<col; j++) {
if(dfs(new boolean[row][col],board,word,0,i,j)) {
return true;
}
}
}
return false;
}
public boolean dfs(boolean[][] isVisit, char[][] board, String word, int index, int row, int col) {
if(board[row][col] != word.charAt(index)) {
return false;
}
//说明找完了
if(index == word.length() - 1) {
return true;
}
isVisit[row][col] = true;
//向上
if(row - 1 >= 0 && !isVisit[row - 1][col]) {
if(dfs(isVisit,board,word,index + 1,row - 1,col)) {
return true;
}
}
//向下
if(row + 1 < board.length && !isVisit[row + 1][col]) {
if(dfs(isVisit,board,word,index + 1,row + 1,col)) {
return true;
}
}
//向左
if(col - 1 >= 0 && !isVisit[row][col - 1]) {
if(dfs(isVisit,board,word,index + 1,row,col - 1)) {
return true;
}
}
//向右
if(col + 1 < board[0].length && !isVisit[row][col + 1]) {
if(dfs(isVisit,board,word,index + 1,row,col + 1)) {
return true;
}
}
//说明改路走不通,选择放弃走这里
isVisit[row][col] = false;
return false;
}
80.删除排序数组中重复项2
这个题原样我们在之前写过,只不过该题是允许重复两次,但是其思路基本没有太大差别,只需要对其中的情况进行讨论即可。
由题可知出现次数是一个分界线
1.times = 1 ,允许下一项重复
2.times = 2,不允许下一项重复
//删除数组重复元素
public int removeDuplicates(int[] nums) {
if(nums.length == 0) {
return 0;
}
//因为我们跳过了第一个,所以下标从 1 开始插入
int index = 1;
//记录重复元素
int prev = nums[0];
//记录重复元素出现次数
int times = 1;
for(int i=1; i<nums.length; i++) {
if(times == 2) {
//仍然重复
if(nums[i] == prev) {
continue;
}
//开始不重复,并更换重复标准元素
prev = nums[i];
nums[index++] = nums[i];
times = 1;
}else { //重复次数不为2
nums[index++] = nums[i];
if(prev == nums[i]) {
times++;
}else {
prev = nums[i];
times = 1;
}
}
}
return index;
}