文章目录
前言
本博客仅做学习笔记,如有侵权,联系后即刻更改
科普:
学习路线
时间/空间复杂度
时间复杂度
时间复杂度考虑最坏时间复杂度
- T(n) = O(f(n))
f(n) 是算法代码执行的总步数,也叫操作数- O(logn)
对于对数复杂度来说,不管是以 2、3 为底,通通记作 O(logn)
- 常见时间复杂度
空间复杂度
在衡量代码的空间复杂度的时候,只关心运行过程中临时占用的内存空间
- n 作为数据集大小,f(n) 指的是规模 n 所占存储空间的函数
堆/栈
程序运行时所需的内存空间分为 固定部分,和可变部分
数组
知识点
for的增强型循环
- 增强for循环遍历数组时使用的普通for循环,而遍历集合时使用的Iterator迭代器
- 在使用增强型for循环不支持遍历时删除元素
- 使用增强型for循环时,对遍历的集合需要做null判断,不然可能引发空指针异常。
快慢指针
- 使用速度不同的指针(可用在链表、数组、序列等上面),来解决一些问题
- 快指针 fast 指向当前要和 val 对比的元素,慢指针 slow 指向将被赋值的位置
滑动窗口
- 一般就用在数组或者字符串上
- 滑动:窗口可以按照一定的方向移动。
- 窗口:窗口大小可以固定,也可以不固定,此时可以向外或者向内,扩容或者缩小窗口直至满足条件
模拟题
- 模拟题本身不涉及算法,就是单纯根据题目所描述的模拟整个过程从而得到最后的结果
力扣704题-二分查找
确定区间为左闭右闭
- 左节点可以等于右节点
- middle要向前/后移动一位
数组的特点
- 数组下标都是从0开始的
- 数组内存空间的地址是连续的
class Solution {
public int search(int[] nums, int target) {
// 避免输入的target过大或过小
if (target < nums[0] || target > nums[nums.length - 1])
return -1;
int left = 0,
right = nums.length-1,
middle;
while(left <= right){
middle = left + (right-left)/2;
if(nums[middle] == target)
return middle;
else if(nums[middle] > target)
right = middle-1;
else
left = middle+1;
}
return -1;
}
}
相关题目
力扣35-搜索插入位置
class Solution {
public int searchInsert(int[] nums, int target) {
int len = nums.length -1;
// 提前判断是否在区间内
if(target < nums[0])
return 0;
else if(target > nums[len])
return len+1;
// 左闭右闭区间
int left = 0, right = len, middle = 0;
while(left <= right){
middle = left + (right - left)/2;
// target在右区间
if(nums[middle] < target)
left = middle+1;
// target在左区间
else if(nums[middle] > target)
right = middle-1;
else return middle;
}
// 目标值插入数组中
return right+1;
}
}
力扣34-在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int location = binarySearch(nums,target);
if(location == -1){
return new int[] {-1,-1};
}
// 确定左右边界
int leftBorder =location ,rightBorder = location;
while(leftBorder-1 >= 0 && nums[leftBorder-1] == nums[location]){
leftBorder--;
}
while(rightBorder+1 < nums.length && nums[rightBorder+1] == nums[location]){
rightBorder++;
}
return new int [] {leftBorder,rightBorder};
}
// 二分查找
public int binarySearch(int[] nums, int target){
int len = nums.length;
// 先判断是否在数组内
if(nums.length == 0)
return -1;
else if(target < nums[0])
return -1;
else if(target > nums[len-1])
return -1;
// 左闭右闭
int left = 0, right = len -1, middle = 0;
while(left <= right){
middle = left + (right-left)/2;
if(target == nums[middle]){
return middle;
}else if(target > nums[middle]){
left = middle +1;
}else {
right = middle -1;
}
}
return -1;
}
}
力扣69-x的平方根
class Solution {
public int mySqrt(int x) {
int left = 0, right = x, middle = 0, ans = -1;
while(left <= right){
middle = left + (right - left)/2;
if((long)middle*middle <= x){
ans = middle;
left = middle +1;
}else
right = middle -1;
}
return ans;
}
}
力扣367-有效的完全平方数
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0, right = num, middle = 0;
while(left <= right){
middle = left + (right - left)/2;
if((long)middle*middle == num){
return true;
}else if((long)middle*middle < num)
left = middle+1;
else right = middle -1;
}
return false;
}
}
力扣27题-移除元素
移除元素
- 是快慢指针的经典题目
暴力双层循环
class Solution {
public int removeElement(int[] nums, int val) {
int num = nums.length;
for(int i=0; i<num; i++){
if(nums[i] == val){
for(int j=i; j<num-1; j++){
nums[j] = nums[j+1];
}
num--;
i --;
}
}
return num;
}
}
快慢指针
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
int fast = 0;
for(; fast<nums.length; fast++){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}
双向指针
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length -1;
while(left <= right){
// 找左边等于val的元素
while(left <= right && nums[left] != val)
left ++;
// 找右边不等于val的元素
while(left <= right && nums[right] == val)
right --;
if(left < right)
nums[left ++] = nums[right --];
}
return left;
}
}
相关题目
力扣26-删除有序数组中的重复项
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0) return 0;
int slowIndex = 0, fastIndex = 0;
while(fastIndex < nums.length){
if(nums[fastIndex] != nums[slowIndex]){
if(fastIndex - slowIndex > 1)
nums[slowIndex+1] = nums[fastIndex];
slowIndex ++;
}
fastIndex ++;
}
return slowIndex +1;
}
}
力扣283-移动零
class Solution {
public void moveZeroes(int[] nums) {
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.length; fastIndex++){
if(nums[fastIndex] != 0)
nums[slowIndex++] = nums[fastIndex];
}
for(int i = slowIndex; i < nums.length; i++){
nums[i] = 0;
}
}
}
力扣844-比较含退格的字符串
使用栈实现退格
class Solution {
public boolean backspaceCompare(String s, String t) {
return resolveStr(s).toString().equals(resolveStr(t).toString());
}
public StringBuilder resolveStr(String s){
StringBuilder sta = new StringBuilder();
for(char ch : s.toCharArray())
if(ch != '#')
sta.append(ch);
else if(sta.length() > 0)
sta.deleteCharAt(sta.length() -1);
return sta;
}
}
双指针从后往前
class Solution {
public boolean backspaceCompare(String S, String T) {
int sSkipNum = 0; // 记录S的#数量
int tSkipNum = 0; // 记录T的#数量
int i = S.length() - 1;
int j = T.length() - 1;
while (true) {
// 从后向前遍历S
while (i >= 0) {
// 如果为#,计数加一
if (S.charAt(i) == '#') sSkipNum++;
else {
// #的计数不为零,要过一轮
if (sSkipNum > 0) sSkipNum--;
// 直到#的个数为0,跳出和T的字符比对
else break;
}
i--;
}
while (j >= 0) {
if (T.charAt(j) == '#') tSkipNum++;
else {
if (tSkipNum > 0) tSkipNum--;
else break;
}
j--;
}
// 先检验 S 或者 T 是否遍历到头了
if (i < 0 || j < 0) break;
// 检验跳出时的字符是否相同,不同则可以跳出最外层循环,返回false
if (S.charAt(i) != T.charAt(j)) return false;
i--;j--;
}
// 说明S和T同时遍历完毕
if (i == -1 && j == -1) return true;
return false;
}
};
力扣977题-有序数组平方排序
双指针法来解决,left 指向下标 0,right 指向下标 n - 1
class Solution {
public int[] sortedSquares(int[] nums) {
int right = nums.length-1, left = 0;
int array[] = new int [nums.length];
int pos = nums.length-1;
while(left <= right){
nums[left] = Math.abs(nums[left]);
nums[right] = Math.abs(nums[right]);
if(nums[left] > nums[right])
array[pos--] = (int)Math.pow(nums[left++], 2);
else {
array[pos--] = (int)Math.pow(nums[right--], 2);
}
}
return array;
}
}
力扣209题-长度最小子数组
滑动窗口
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int right=0, left=0, sum=0, num=Integer.MAX_VALUE;
for(; right<nums.length;){
sum += nums[right++];
while(sum >= target){
num = Math.min(num, right-left);
sum -= nums[left++];
}
}
return num == Integer.MAX_VALUE ? 0 : num;
}
}
力扣59题-螺旋矩阵
题目解析
这是一道模拟题,难度中等,面试出现频率极高时空复杂度分析
矩阵大小为 n²,需要全部遍历且填充,所以时间复杂度为 O(n²)
此外额外维护了一个大小为 n² 的结果矩阵,所以空间复杂度为 O(n²)
class Solution {
public int[][] generateMatrix(int n) {
int w[][]= new int [n][n];
int s=0,x=n-1,z=0,r=n-1;
int sum=1,i;
while(sum <= n*n){
for(i=z; i<=r; i++)
w[s][i] = sum++;
s++;
for(i=s; i<=x; i++)
w[i][r] = sum++;
r--;
for(i=r; i>=z; i--)
w[x][i] = sum++;
x--;
for(i=x; i>=s; i--)
w[i][z] = sum++;
z++;
}
return w;
}
}
总结
小小励志
有些事你现在不做,一辈子都不会做了。
如果你想做一件事,全世界都会为你让路。
《搭车去柏林》