前段时间工作很忙,也一直在专注于业务,没有时间做一些技术的总结,脑子容易生锈,作为一名技术人,尤其是在参加工作的前5年,甚至10年内,时刻警醒自己技术才是自己的核心竞争力,LeetCode题是很好的一种给大脑‘除锈’的方式,所以,有空做做不仅对参加面试有帮助,同时也能让大脑动一动,偶尔工作中也能用到,一举三得,岂不美哉。
更新ING。
基础算法
/**
* leetcode题:无
* 方法:二分搜索
* 思想:存在很多变种,所以基础必须很熟练
* @return
*/
public int myBinarySearch(int[] arr,int value) {
int p1=0;
int p2=arr.length-1;
int mid;
while(p1<=p2){
mid=(p1+p2)/2;
if(arr[mid]==value){
return mid;
}else if(arr[mid]<value){
p1=mid+1;
}else {
p2=mid-1;
}
}
return -1;
}
/**
* leetcode题:无
* 方法:快排
* 思想:nlogn的排序,经常用到,需要熟记
* @return
*/
private void QuickSort(int[] nums, int left, int right) {
if(left>=right){
return;
}
//设置left为基准
int key=nums[left];
int i=left;
int j=right;
//设置临时变量
int tmp;
//直到key右边都比他大,左边都比他小
while (i<j){
//从右往左找第一个比key小的
while(nums[j]>=key && i<j){
j--;
}
//从左右找第一个比key大的
while (nums[i]<=key && i<j){
i++;
}
//将两个数交换位置
if(i<j){
tmp=nums[i];
nums[i]=nums[j];
nums[j]=tmp;
}
}
//将key放到中间位置,一次循环结束,重新设置基准,并左右继续
nums[left]= nums[i];
nums[i]=key;
QuickSort(nums,left,i-1);
QuickSort(nums,i+1,right);
}
二分法变种
/**
* leetcode题:搜索旋转排序数组
* 方法:二分搜索变种
* 思想:根据题目条件切换二分法变种思想
* @return
*/
public int search(int[] nums, int target) {
int p1=0;
int p2=nums.length-1;
int mid;
while(p1<=p2){
mid=(p1+p2)/2;
if(nums[mid]==target){
return mid;
}
//左侧有序
if(nums[mid]>nums[p1]){
//数据在左边区间
if(nums[mid]>target && nums[p1]<=target){
p2=mid-1;
}else {
//数据在左边区间
p1=mid+1;
}
}
//右侧有序
else {
//旋转边界正好是mid的情况
if(mid==p2){
return -1;
}else if(nums[mid+1]==target){
return mid+1;
}
//其它情况
if(nums[mid+1]<target && nums[p2]>=target){
p1=mid+2;
}else {
p2=mid-1;
}
}
}
return -1;
}
DFS/回溯
//基本思路
def dfs(n){ //可以描述阶段的状态
if(valid) {收集结果,返回} //出口条件
if(pruning) return; //剪枝,这一步是为了加快回溯过程,降低程序执行时间
for(i:1~p){ //选择该阶段的所有决策
选择可行决策; //剪枝的一种
add; //标记已访问该点
DFS(n+1); //进入下一阶段
recover; //还原
}
}
/**
* leetcode题:最大岛屿面积
* 方法:DFS(深度优先搜索算法)
* 思想:根据题目条件和特点,分析递归终止条件,树分支延伸条件
* @param grid
* @return
*/
public int maxAreaOfIsland(int[][] grid) {
int result=0;
//遍历数组所有节点,并将最大值保存在result中
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
//沿着条件递归搜索
int mid=dfs(grid,i,j);
//每次结果都记录最大值
result=Math.max(mid,result);
}
}
return result;
}
private int dfs(int[][] grid,int i,int j){
//递归终止条件:超过数组范围
if(i<0 || j<0 || i>grid.length || j>grid[0].length){
return 0;
}
//如果为0则不符合题目逻辑
if(grid[i][j]==0){
return 0;
}
//将扫过的节点置0(即每个岛屿最多只被计算一次,符合题目逻辑)
grid[i][j]=0;
//递归真正条件:返回当前节点的上下左右节点的和(岛屿只有0和1)
return 1
+dfs(grid,i-1,j)
+dfs(grid,i+1,j)
+dfs(grid,i,j-1)
+dfs(grid,i,j+1);
}
/**
* leetcode题:第k个排列
* 方法:DFS(深度优先搜索算法)/回溯变种
* 思想:1.需要很熟练基本的回溯写法 2.根据条件进行剪纸
* @param grid
* @return
*/
private volatile int count;
public String getPermutation(int n, int k) {
boolean[] visited = new boolean[n];
List<Integer> resultList = dfs(n,k,visited,new LinkedList<>());
StringBuffer result=new StringBuffer();
for(Integer one:resultList){
result.append(one);
}
return result.toString();
}
private LinkedList dfs(int n,int k,boolean[] visited,LinkedList<Integer> result){
//单次回溯终止条件
if(result.size()==n){
count++;
return result;
}
for(int i=1;i<=n;i++){
if(!visited[i-1]){
visited[i-1]=true;
result.add();
result=dfs(n,k,visited,result);
if (count == k) {
return result;
}
result.removeLast();
visited[i-1]=false;
}
}
return result;
}
/**
* leetcode题:朋友圈
* 方法:DFS(深度优先搜索算法)
* 思想:1.深入理解题意,1个人只能在一个朋友圈中,有N个人,所以从0~N开始遍历
* @param M
* @return
*/
public int findCircleNum(int[][] M) {
int l=M.length;
int res=0;
boolean[] visited=new boolean[l];
//从0开始遍历朋友圈
for(int i=0;i<l;i++){
if(!visited[i]){
dfs(M,visited,i);
res++;
}
}
return res;
}
private void dfs(int[][] M,boolean[] visited,int i){
//确保每个朋友只在一个朋友圈里面出现
if(visited[i]){
return;
}
visited[i]=true;
for(int j=0;j<M.length;j++){
if(M[i][j]==1){
//如果i j是朋友,再继续遍历j的朋友
dfs(M,visited,j);
}
}
}
双指针/滑动窗口
/**
* leetcode题:最长连续递增序列
* 方法:双指针滑动窗口
* 思想:easy题,比较简单,适合拿来联系边界处理
* @return
*/
public int findLengthOfLCIS(int[] nums) {
int l=nums.length;
if(l<=0){
return 0;
}else if(l==1){
return 1;
}
int p1=0;
int p2=1;
int res=1;
while(p2<l){
if(nums[p2]>nums[p2-1]){
res=Math.max(res,p2-p1+1);
p2++;
}else {
p2++;
p1=p2-1;
}
}
return res;
}
/**
* leetcode题:合并区间
* 方法:滑动指针
* 思想:1.指定当前滑动指针,持续与下一个比较
* @param intervals
* @return
*/
public int[][] merge(int[][] intervals) {
if(intervals.length==0){
return intervals;
}
Arrays.sort(intervals,(v1, v2)->v1[0]-v2[0]);
int l=intervals.length;
int[][] res = new int[l][2];
int n=0;
int p1=intervals[0][0];
int p2=intervals[0][1];
for(int i=0;i<intervals.length;i++){
if(i!=intervals.length-1 && p2>=intervals[i+1][0]){
p2=Math.max(p2,intervals[i+1][1]);
}else {
res[n][0]=p1;
res[n][1]=p2;
if(i!=intervals.length-1){
p1=intervals[i+1][0];
p2=intervals[i+1][1];
}
n++;
}
}
return Arrays.copyOf(res,n);
}
动态规划
/**
* leetcode题:接雨水
* 方法:动态规划
* 思想:1.根据题目,分析左右边界本身三者之间的关系
* @param height
* @return
*/
public int trap(int[] height) {
int ans=0;
int len=height.length;
if(len==0){
return 0;
}
int left_max_arr[]=new int[len];
int right_max_arr[]=new int[len];
left_max_arr[0]=height[0];
right_max_arr[len-1]=height[len-1];
for(int i=1;i<len;i++){
left_max_arr[i]=Math.max(left_max_arr[i-1],height[i]);
}
for(int j=len-2;j>=0;j--){
right_max_arr[j]=Math.max(height[j],right_max_arr[j+1]);
}
for(int k=0;k<len;k++){
ans=ans+Math.min(left_max_arr[k],right_max_arr[k])-height[k];
}
return ans;
}
其它
/**
* leetcode题:最长连续序列
* 方法:哈希表
* 思想:灵活使用HashSet,注意防止倒退的条件,以及数据累加的条件
* @return
*/
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int one:nums){
set.add(one);
}
int result=0;
for(int one:set){
int mid = 1;
if(!set.contains(one-1)){
int cur=one;
while (set.contains(cur+1)){
mid++;
cur++;
}
result=Math.max(result,mid);
}
}
return result;
}