自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(58)
  • 收藏
  • 关注

原创 排列5.字母大小写全排列

可以用回溯来做,不过就两种 情况,把目前在遍历的字母变成大写或者不变大写两种,所以不用for循环class Solution { List<String> res=new ArrayList<String>(); public List<String> letterCasePermutation(String S) { if(S.length()==0)return res; core(S.toCharArray(),

2021-01-31 22:37:43 374

原创 组合5.电话号码的字母组合

可以从中看到这个是类似于组合的,比如给的数字是234,则可以选一个数字,从2开始选字母,则3选的时候就不能选2了。所以理应用begin来限制下次选的时候选的2中选过的字母,但这个题比较特殊的是他们的数组是分开的,也就是向下递归到3时也应该从0开始,所以就不用begin。class Solution { List<String> res=new ArrayList<String>(); public List<String> letterCombinati

2021-01-31 21:51:14 100

原创 完全背包1.换钱的最少货币数322

给一个钱金额的数组和一个目标值,可以无限取钱的数量,求最少的可以达到目标值的硬币数。因为硬币的数量是无限的,子问题之间没有限制,所以具有最优子结构,可以以用动态规划来解。求f(i)可由f(i-1)得到,要得出状态转移方程,(1)首先确定基础例子,也就是target为0时k也为0、(2)然后确定状态,也就是原问题和子问题之间变化的量,也就是target值。(3)接着确定选择,也就是导致状态变化的行为,是目前硬币的count(4)dp函数的意义,一般其中的参数是原问题和子问题之间变化的量,而值本身是

2021-01-31 15:50:13 127

原创 前缀树(字典树)1.单词替换

需要把一个句子中的单词全部替换为它的前缀,前缀越短越好则可以使用前缀树,将前缀存到树中,在树上找单词的最短前缀。字典树TrieNode可以自己定义,保存一些字符串与值的关系,类似hashmap,都是key-value映射,只不过TrieNode的key只能是字符串时间复杂度非常低,插入和查询都是O(k),但空间复杂度高。里面可以有三个量,分别是count来统计单词前缀出现的次数,next是一个指向子节点的数组(其中有26个位置来存26个字母),还有count表示到这是否存这一个完整的单词。也就是说它

2021-01-28 16:52:13 125 1

原创 排列4.括号生成(特殊条件的排列)

根据题目可以画出回溯树,非常直观,需要处理的就是何时回溯,结束递归条件是此时长度达到规定长度。如果此时左括号数量小于n,则继续添加左括号。如果左括号数量大于右括号,则添加右括号。class Solution { List<String> res=new ArrayList<String>(); public List<String> generateParenthesis(int n) { if(n==0)return res;

2021-01-28 10:50:34 343

原创 二维数组4.求全为1正方形221/1277

求最大正方形f[i][j]表示的含义有两个,第一是以ij结尾的正方形的边长,第二是以这个点为右下角结尾正方形的个数 ,为什么它可以代表个数,因为都全1了,所以其他更少长度为边长的正方形肯定更定也是存在的。所以可以得出dp[i][j]为其他周围三个点的最小值,因为只有全为1他才可能为1.按照这个即可求出,class Solution { public int maximalSquare(char[][] matrix) { int[][] dp=new int[matrix.le

2021-01-27 14:11:35 288

原创 子序列4.最长公共子序列LCS

对于两个字符串的动态规划问题,就是建立一个二维数组dp[i][j]的意思就是arr1[0]到arr1[i]和arr2[0]到arr2[j]他们的最长公共子序列的长度是dp[i][j]第一行和第一列肯定都是初始化为1的。选择状态方程时其实就是选择每个字符要还是不要,这个题选择的关键就是这个字符要都存在于两个字符串中。所以遍历条件就是是否相等,相等则dp[i][j]=dp[i-1][j-1]+1;不相等则p[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);有一个非常好用的

2021-01-27 12:43:01 68

原创 子序列1.最长递增子序列

求的是子序列而不是子数组,利用滑动窗口显然解不了,应该使用动态规划。利用f(i)表示以第i个元素为结尾的递增子序列的长度。则f(i)=max(f(j))+1;能添加j的要求就是nums[j]<nums[i];所以每求一个值都要遍历前面的值来求前面符合要求而且最大的值。class Solution { public int lengthOfLIS(int[] nums) { if(nums.length==0)return 0; int[] dp=new

2021-01-27 10:23:58 118

原创 二维数组3.最小路径和

与不同路径相似,不同在于初始化和状态方程的不同。class Solution { public int minPathSum(int[][] grid) { int[][] dp=new int[grid.length][grid[0].length]; dp[0][0]=grid[0][0]; for(int i=1;i<grid.length;i++){ dp[i][0]=grid[i][0]+dp[i-1][0];

2021-01-26 19:54:00 144

原创 二维数组2.不同路径

求一个机器人从(0,0)走到(m,n)的路径数量,只能往下或者往右移动一步。f(i,j)表示从(0,0)走到(i,j)的路径数量,则f(i,j)=f(i-1,j)+f(i,j-1),画图可以很轻松的看出怎么求每个位置和初始赋值,第一行和第一列全都是1,然后求出即可。这样的时间复杂度为O(mn),空间复杂度为O(mn)class Solution { public int uniquePaths(int m, int n) { int[][] dp=new int[m][n];

2021-01-26 13:09:48 198

原创 二分7.求一个排序数组中一个数的第一个和最后一个位置

就是分成两个函数来分别求数组中的数的位置,有注意的就是就算等于目标数也不结束,所以要写if,else if 和else,别分开。class Solution { public int[] searchRange(int[] nums, int target) { if(nums==null || nums.length==0)return new int[]{-1,-1}; int start=binarySerchStart(nums,target,0,nums.

2021-01-25 21:56:41 108

原创 二分6.旋转数组plus

要在旋转数组中找到给定的值,就需要分情况讨论了,重点是找到分割后的两部分哪部分是有序的,根据有序的部分可以找到向哪继续下一步的查找第一种情况,0到mid没旋转有序,则若目标值在mid和lo之间, 则hi=mid第二种情况,0到mid没旋转,要找的值在mid到hi,则lo=mid第三种情况,0到mid旋转了,要找的...

2021-01-25 19:28:46 57

原创 后序遍历DFS1.删除给定值的叶子节点(删除节点)

首先想这个题的普通节点怎么做,首先删除它的子节点的叶子节点,如果返回来时它自己成了叶子节点,则要删除它自己,所以很显然是后序遍历。然后就是怎么删除自己的问题,要删除自己,就返回null,然后让自己的父节点接到自己时将其删除。class Solution { public TreeNode removeLeafNodes(TreeNode root, int target) { if(root==null)return null; TreeNode left=rem

2021-01-24 17:30:50 268

原创 后序遍历DFS2.求两个节点在二叉树中的最近公共节点

要求两个节点的公共节点,则肯定是从这个节点

2021-01-24 14:48:59 115

原创 递归4.填充每个节点的下一个右侧指针116

从一个普通节点入手,首先这不是子节点可以完成的事情,不用创建递归函数,从头结点出发,交换左右一直到最后class Solution { public TreeNode invertTree(TreeNode root) { if(root==null)return null; TreeNode node=root.left; root.left=root.right; root.right=node; invertTr

2021-01-24 14:17:09 73

原创 单调栈3.拼接最大数

与从一个数组中去除k个数类似,只不过现在是从两个数组中选k个数使其最大,不能改变相对位置,所以需要归并(在未排序的数组中归并)也就是分别在第一个数组中选k1个数,在第二个数组中选k2个数,然后将他们组合成一个最大的数。分成归和并两步。选k1个数就利用单调栈来选,选出来是一个单调递减的数组,归并就利用哪个大归并哪个来做。那怎么确定哪个数组选几个呢,如果第一个数组的长度为m。第二个数组的长度为n,那么k1要大于0小于m,k2要大于0小于n,k1+k2=k,需要遍历所有x和y可能的值。k2等于k-k1,所以

2021-01-21 16:37:24 79

原创 单调栈2.去除重复字母

去除字符串中的重复字母,并使得剩下的字符串的字典序最小。仍然类似于去掉k个字母,但此题没有k,而是换成了重复字母的个数,每一个字母都有一个次数。可以先用一个哈希表来记录这种关系。但遍历完成后不能知道有哪些字母没有被除干净,也不能向去除k个数字一样去掉后面的,所以只能换一种方法。设置一个map来表示每个字母出现的次数。设置一个exist数组来表示此时的字符是否已经加入过栈,任何时候栈中只能出现一个字母的一次。如果没有加入过,则可加入,如果加入过,就直接跳过,并让这个字母出现的次数-1(也就是后面还会

2021-01-20 22:12:48 108

原创 单调栈1.去掉k位数字使剩下的数字最小

核心就是贪心 ,优先丢弃前面的使得满足要求。保持字符串相对位置不变的去字符比大小题去掉k位数字使剩下的数字最小我们需要去掉k个数并使剩下的数字最小。所以思路就是遍历数组,面对每一个数字都选择去掉或是保留,因为两个相同位数的数字比较就是通过第一个不同的数字来比较的。利用单调栈来保存留下的的数字,对这个题来说是单调递增栈,因为前面的数字越小,会使得留下的数字越小,所以要优先把前面大的数字去掉。使用单调栈,1.如果当前元素小于栈顶元素,则将栈顶元素出栈(因为保留当前这个元素更好)每丢弃一次都使得k减

2021-01-20 20:01:46 213

原创 栈2.基本计算器

处理一个字符串,计算这个字符串的值,符号有加号,减号,空格,括号本质上处理字符串就是要延迟主表达式的处理过程,优先计算括号内的表达式将元素一个个的添加到栈里,直到遇到一个右括号,这时优先计算这个括号内的内容,所以要弹出栈中的内容直到遇到左括号。在计算的过程中,由于所有的数都是逆向弹出的,所以不好计算其中的减法,我们需要把所有的计算都看成加法,把减法看成负数。当迭代遇到一个数字时,要将此数字加上之前得到的操作数乘10当迭代遇到一个+或者-时,就将上一个操作数以及符号计算到结果中,然后将符号赋值给下次运

2021-01-20 17:51:18 94

原创 一维数组字符串2.最长有效括号

有一个只包含()的字符串,找出其中最长的有效的括号子串。栈利用栈,我们遇到(的时候将它的下标放入栈中,遇到)时先将栈顶元素弹出(也就是它的左括号),如果此时栈中没有元素,则说明此时之前的所有括号都被分配完,这就是最后一个匹配的有效右括号,将它的坐标放入栈中。如果此时栈不为空,将res更新为以此时右括号结尾的字符串的长度,为原来res和i-stack.peek()的较大值。class Solution { public int longestValidParentheses(String s)

2021-01-20 16:32:40 151

原创 栈1.有效的括号

判断一个只包含三种括号的字符串是否符合括号规范。如果括号顺序是正确的,那么用栈来保存括号,碰到左括号时入栈,碰到右括号时出栈,则遍历完成之后栈是空的。是否正确不仅与括号的数量有关,还与括号的位置有关.map中key是)而value是(的原因是这样可以在碰到)的时候方便的判断它是否为对应的括号。class Solution { public boolean isValid(String s) { if(s.length()%2==1)return false;

2021-01-20 14:39:46 96

原创 最长连续序列

给一个未排序的序列,找出其中最长的连续序列的长度。对于每个数都查找在数组中有没有x+1,x+2一直到最长。可以用一个hashset来存储数组中的数,这样可以很方便的判断有没有x+1…,但这样还是外层循环一次,内部循环o(n),因为当找到x到x+n是连续数组后,碰到x+1还要重新找一遍,则在外部遍历的时候,如果找到x-1存在,则从x开始就不可能是最长了,直接跳过。class Solution { public int longestConsecutive(int[] nums) {

2021-01-19 23:07:28 59

原创 并查集--使数组唯一的最小增量945

可以让数组中的某个数加1,求加几次之后数组中所有的数都是唯一的。先将数组排序,现在遍历数组,如果当前数大于等于前一个数加1,则说明不用处理,令前一个数等于当前数,如果小于前一个数加1,则要把它变到前一个数加1,并把前一个数变成前一个数加1.class Solution { public int minIncrementForUnique(int[] A) { if(A==null || A.length<2)return 0; Arrays.sort(A);

2021-01-19 22:55:12 87

原创 最短无序子数组

求一个数组的最短无序子数组,左边界是由数组的无序部分的最小元素的位置决定的,右边界是由数组无序部分的最大元素的位置决定的。所以遍历数组,找到第一个降序开始的最小元素,然后从右开始找第一个升序开始的最大元素,接着找到他们的正确位置,输出长度。class Solution { public int findUnsortedSubarray(int[] nums) { if(nums==null || nums.length==0 || nums.length==1)return 0;

2021-01-19 17:42:54 112

原创 打乱数组

用构造函数初始化输出的数组。reset()返回这个数组的原态。shuffle()返回一个数组的打乱结果用的是Fisher-Yates 洗牌算法,要让数组的每个排列出现的概率一样,n个字符的数组有n!个排序,为了将这些顺序编码,就得log(n!)个字符时间复杂度为O(n),空间复杂度为O(n)来存储之前的数组。重排的步骤就是遍历数组,并生成一个当前下标到末尾的随机下标,然后将当前小标值和随机下标值交换。class Solution { int[] array; int[] orig

2021-01-19 16:53:07 65

原创 矩阵置零(原地变换)

将矩阵中0元素的行和列都变成0,如果正常做非常好做,只要遍历一遍记录0的位置,然后第二遍遍历将该行和列变成0即可。但这样需要用到空间复杂度为O(mn)时间O(m+n)第二种在找0 的过程中就把矩阵中的行和列都变成一个设置的值(不是0),第二遍遍历将这种值的位置都变成0,但这样每个0元素都会遍历m+n次,所以为O(mn)*(m+n)空间为O(1)第三种在找到0后将列首和行首的两个元素变成0,这样只需遍历两个即可给行和列赋值,不用重复赋值,但要注意第一行和第一列的第一个都是0,0,所以需要额外用一个变量标志

2021-01-19 13:26:34 1288

原创 阶乘后的零

求阶乘后一个数的最后有几个零,单算阶乘很好算,算一个树后面有几个零就看它能不能被10整除,也就是%10==0,可以判断有几个零。但这样复杂度太高,需要用O(logn)的时间复杂度。算阶乘末尾有0代表它乘了个10,可以由2乘5得到,那么算阶乘中有多少对2*5因子就可以得到有多少个0,所以看n!中有多少个有5的因子,有多少个有2 的 因子就行,5的数量肯定少于2,所以按5来。但每个数不一定就是加1,比如25,有两个5的因子,所以要算每个数有几个5的因子,除以5可整除则可加1.还可以发现算5的倍数就可以,所

2021-01-17 12:59:49 241

原创 字符串相乘(大数相乘)

用两个指针在字符串上移动来模拟竖式乘法首先一个字符串的最低位乘另一个字符串的最低位,然后另一个字符串的指针移动,乘后得到另一个数字,如果一个数字的指针是i,另一个数字为j,则他们相加得到的res的位数是i+j和i+j+1这两位真的比其他简单好多。class Solution { public String multiply(String num1, String num2) { if(num1.equals("0") || num2.equals("0"))return "0"

2021-01-17 10:55:49 229

原创 不转换成字符串求一个数是否为回文数

将一个数完全反转后再比较可能会溢出,所以其实只要把后半部分反转即可,很容易得到数字后面的数字,怎么判断转换一半了,当原始数字小于反转数时就说明转换一半了。但要注意的是可能是奇数位数的数字,所以判断的时候判断revx 和rev/10x。需要在开始判断特殊情况,如果x为0则返回true,如果x<0或者最后一位为0则返回falseclass Solution { public boolean isPalindrome(int x) { if(x==0) return true;

2021-01-17 09:59:16 217 1

原创 字符串转换为整数

首先变成字符数组,然后循环去掉空格(利用index++来控制),然后判断第一个字符是不是+或者是-,是负的话设置符号位为-1准备最后乘。然后进入while循环,如果不是数字,退出。如果此时的res大于除以10的最大值或者等于但加上后大于则返回最大值,小于最小值则返回最小值。最后一步加上res。public class Solution { public int myAtoi(String str) { int len = str.length(); char[]

2021-01-17 09:34:49 103

原创 求整数反转值

从最低位开始,并把它加到rev上,加的时候要把原来的rev乘10再加,这样就可以实现最后的最低位变到最高位。但是要注意的是加后这个可能溢出,所以加之前要检查rev/10是否超过范围。class Solution { public int reverse(int x) { int res=0; while(x!=0){ int t=x%10; x=x/10; if(res>Integer.

2021-01-17 09:18:30 110

原创 划分字母区间

要找到最多的片,且每个字母最多出现在同一个字符串中,所以一个片段的开始的字母肯定等于最后的字母,要让片数最多,则片段之间的距离要尽可能短。首先利用遍历找到每个字母的最后位置,然后再次利用双指针维护此时片段的开始和结束位置。然后读取当前位置字母的结束值,end等于读取过字母中最远距离的end,但一旦到达这个end,相对于其他片段来说已经是最短了。完成这个片段,后面进行下一个片段的读取。class Solution { public List<Integer> partitionLabe

2021-01-16 18:28:38 87

原创 Z字形变换(按行来读取以列排列的字符串)

因为给的字符串是以n行的倒z字按列排列的,现在要按行读,那就可以先读出每一行,然后将所有行拼在一起,但读的时候还是按原来的顺序按列读,只不过是分到不同的行。因为是按倒z字排列,所以每当读到第一行和最后一行的时候就要改变分配行的方向,利用一个flag就可以实现当前分配行是加还是减。import java.util.ArrayList;class Solution { public String convert(String s, int numRows) { if(s==null

2021-01-16 12:04:55 257 1

原创 双指针7.快乐数(快慢指针)

各位平方和趋于1的数为快乐数,也就是不断算一个数的各位平方和,最后的情况可能趋于三种情况,第一种是趋于1,第二种是不断循环,第三是趋于无穷大,其实的第三种永远不会发生,因为对于3位数的数来说,下一位永远不可能大于243,4位及以上的数每次都会丢失直到3位。所以只有两种情况。所以我们要先算这个数的平方和,然后判断这个数是否已经出现过了,用hashset来记录,但这样用的空间太多了,其实这样得到的是一个隐式链表,判断有没有环就用快慢指针。class Solution { public boolean

2021-01-16 09:38:03 127

原创 买卖股票2.买卖股票的时机(可多次交易)

可无数次交易(必须交易完成后再进行)因为可以多次交易,所以和1的区别只有状态方程不同如果今天结束后持股,则可能是昨天没持股,今天持股,也可能是昨天就持股如果今天结束后不持股,则可能是昨天持股,今天卖了,也可能是昨天就不持股。class Solution { public int maxProfit(int[] prices) { int len = prices.length; if (len < 2) { return 0;

2021-01-16 01:07:09 360

原创 买卖股票1.买卖股票最佳时机

求一个数组中买卖股票得到的最大利润‘遍历数组,因为只能先买后卖,所以每次遍历都更新此时的最小值,更新最小值之后不能卖,如果没有更新最小值,则看此时的价格卖能不能得到最大利润,进行比较。class Solution { public int maxProfit(int[] prices) { if(prices==null || prices.length==0 || prices.length==1)return 0; int maxpro=Integer.MI

2021-01-15 23:29:53 58

原创 双指针6.接雨水(异向指针)42

接雨水与最多装水容器相比,最多装水容器可以直接计算出最多的,面积相对比较好算,而接雨水需要算每一个位置可以装的雨水,这个位置可以装的水为长乘宽,长为1,宽为最小减现在的y值。暴力需要双层循环O(n)如果存储左右的最大值,并且每移动一次都更新一次,则时间O(n),空间O(n)双指针:如果使用双指针从两边开始的话,在遍历的过程中就可以算到两边的可以接雨水的值,就可以省去在过程中的空间使用。class Solution { public int trap(int[] height) {

2021-01-15 18:49:50 56

原创 旋转链表61

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。这个题的k可能大于length,而且大于之后还要继续旋转,所以需要先遍历得到长度,然后再令k=k%length。利用快慢指针 就可以得到倒数第k个节点,完成指针的重定位。有特殊情况比如k=0的时候怎么做,可以根据情况来安排。class Solution { public ListNode rotateRight(ListNode head, int k) { if(head==null)retur

2021-01-15 14:41:43 62

原创 层序遍历BFS5.层数最深的叶子节点的和

求层数最深的节点和,那也是一层的,直接利用层序遍历,返回最后一层的和,每层遍历开始前清空res,最后一层则不会被清空import java.util.LinkedList;class Solution { public int deepestLeavesSum(TreeNode root) { if(root==null)return 0; Queue<TreeNode> q=new LinkedList<TreeNode>();

2021-01-14 18:31:18 89

原创 层序遍历BFS4.二叉树的堂兄弟节点

这个题既然堂兄弟节点在同一层,就可以利用层序遍历来锁定一层,然后目的是找到这两个节点的父节点,如果找到两个节点且父节点不是同一个则返回true。如果都没找到则下一层。如果一层找到一个,则肯定不在一层,返回false。import java.util.LinkedList;class Solution { public boolean isCousins(TreeNode root, int x, int y) { if(root==null ||x==root.val || y=

2021-01-14 18:19:46 93

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除