力扣的错题以及解法个人总结
- LeetCode1:两数之和
- LeetCode20:有效的括号
- LeetCode21:合并两个有序链表
- LeetCode121:买卖股票的最佳时机
- LeetCode125:验证回文串
- LeetCode226:翻转二叉树
- LeetCode242:有效的字母异位词
- LeetCode704:二分查找
- LeetCode733:图像渲染
- LeetCode53:最大子数组和
- LeetCode235:二叉搜索树的最近公共祖先
- LeetCode110:平衡二叉树
- LeetCode141:环形链表
LeetCode1:两数之和
解法一:暴力破解
直接用两个for循环,把一个数和它后面所有的数逐一比较,相加等于target的值反复对应的下标
//暴力解法
public int[] twoSum(int[] nums, int target) {
int[] index = new int[2];
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]+nums[j]==target){
index[0] = i;
index[1] = j;
}
}
}
return index;
}
解法二:利用hashmap来处理
先遍历数组的每一数,且每次把当前数的补数作为key,下标作为value存如hashmap中,然后每次循环时判断当前数的补数是否存在与hashmap中,存在的话返回当前下标和目标map的value值
public int[] twoSum2(int[] nums, int target) {
int[] indexs = new int[2];
//建立k-v , 一一对应的哈希表
HashMap<Integer,Integer> hash = new HashMap<Integer,Integer>();
for(int i = 0;i<nums.length;i++){
if(hash.containsKey(nums[i])){
indexs[0] = i;
indexs[1] = hash.get(nums[i]);
return indexs;
}
//将数据存入key为补数,value为下标
hash.put(target-nums[i],i);
}
return indexs;
}
HashMap的一些用法
- HashMap.containsKey (Object key),如果 hashMap 中存在指定的 key 对应的映射关系返回 true,否则返回 false。 检查key是否存在
- HashMap.get(key),通过key来获取相应的value
- HashMap.put(key,value)想hashMap中添加元素
LeetCode20:有效的括号
解法一:
使用栈的典型例题,先创建栈,把字符串转换为字符数组进行遍历,先把第一个元素对应的元素放进栈,后面的元素是左括号的时候就存进栈,是右括号类型的就会先判断栈是否为空或弹出一个栈顶的元素和当前值进行比较不相等的话就直接返回false,直到遍历完整个字符数组,直接返回stack.isEmpty,为空时返回true说明字符串完全匹配,返回false则说明字符串不符合规范。
public static boolean isValid(String s) {
Stack<Character> stack=new Stack<Character>();
for(char c : s.toCharArray()){
if(c=='('){
stack.push(')');
}else if(c=='['){
stack.push(']');
}else if(c=='{'){
stack.push('}');
}else if(stack.isEmpty()||c!=stack.pop()){
return false;
}
}
return stack.isEmpty();
}
- string.toCharArray():将字符串对象中的字符转换为一个字符数组
- stack.push(E item) 入栈,将项目推送到此堆栈的顶部
- stack.pop 出栈,删除此堆栈顶部的对象,并将该对象作为此函数的值返回
- stack.peek 栈顶元素,查看此堆栈顶部的对象,而不从堆栈中删除它
- stack.isEmpty 判读此堆栈是否为空
LeetCode21:合并两个有序链表
解法一:构建新链表,通过递归将两个链表的值较小的那个插入新链表中。
对比两个链表把较小的值插入新链表中,最后得到的就是一个升序序列
if(list1 == null) {return list2;}
if(list2 == null) {return list1;}
ListNode listNode = new ListNode();
if(list1.val > list2.val){
listNode.val = list2.val;
list2 = list2.next;
}else{
listNode.val = list1.val;
list1 = list1.next;
}
ListNode tmp = mergeTwoLists(list1,list2);
//递归查找
listNode.next = tmp;
return listNode;
- list.val指的的当前结点的值
- list.next指的是指向链表下一个结点的指针
LeetCode121:买卖股票的最佳时机
方法一:DP思想
1.记录之前买入的最小值
2.计算出今天之前最小值买入,今天卖出的获利,也就是今天卖出的最大获利
3.比较每天的最大获利,取最大值即可
public int maxProfit(int[] prices) {
if(prices.length<=1){
return 0;
}
int min = prices[0],max=0;
for(int i=1;i<prices.length;i++){
max = Math.max(max,prices[i]-min);
min = Math.min(min,prices[i]);
}
return max;
}
- 比较最大(小)值的方法Math.max(int a,int b) or Math.min(int a,int b)
- 数组中找最大值
int max=arr[0]
for(int i=0;i<arr.length;i++){
max=arr[i] > max ? arr[i] : max;
}
LeetCode125:验证回文串
方法一:双指针比较
先将字符串放进的StringBuffer区域,然后循环i<=j(i是头指针i=0,j是为指针j=sb.length()-1),两边向中间靠逐一比较指针指向的值直到退出循环,如果都相等就返回true,为回文串,如果有不相等就返回false,该字符串不是回文串。
public boolean isPalindrome(String s) {
StringBuffer sb = new StringBuffer();
for(int i=0;i>s.length();i++){
char temp=s.charAt(i);
if(temp >= '0' && temp <= '9'){
sb.append(temp);
}else if(temp > 'a' && temp <= 'z'){
sb.append(temp);
}else if(temp >= 'A' && temp <='Z'){
sb.append((char)(temp+32));
}
}
int i=0,j=sb.length()-1;
while(i<=j){
if(sb.charAt(i) == sb.charAt(j)){
i++;
j--;
}else{
return false;
}
}
return true;
}
- char类型的数据参与运行会先转换成int类型(ASCII编码表‘A’对应十进制65,‘a’对应的十进制为97),所以(char)(temp+32)为大写转换成小写,即’A’转换成’a’
- 对字符串操作的方法,应该把字符串s存入StringBuffer区再进行操作
LeetCode226:翻转二叉树
方法一:将右节点的值暂存,通过递归然后交换左右节点的值。
public TreeNode invertTree(TreeNode root) {
//先序遍历--从顶向下交换 根左右
if(root == null) return null;
//保护右子树
TreeNode rightTree = root.right;
//交换左右子树的位置
root.right = invertTree(root.left);
root.left = invertTree(rightTree);
return root;
//中序遍历 左根右
if(root == null) return null;
invertTree(root.left);//递归找到左结点
TreeNode rightNode = root.right; //保存右节点
root.right = root.left;
root.left = rightNode;
//递归找到右节点 继续交换 : 因为此时左右节点已经交换了,所以此时的右节点为root.left
invertTree(root.left);
//后序遍历-- 从下向上交换 左右根
if(root == null) return null;
TreeNode leftNode = invertTree(root.left);
TreeNode rightNode = invertTree(root.right);
root.right = leftNode;
root.leftNode = rightNode;
return root;
//利用层次遍历 广度遍历 直接左右交换即可
if(root == null) return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
TreeNode rightTree = node.right;
node.right=node.left;
node.left=rightTree;
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
return root;
}
}
- 前序遍历(根左右),中序遍历(左根右),后序遍历(左右根)
LeetCode242:有效的字母异位词
解法一:把字符串转成字符数组,arrays.sort排序后比较两个值是否相等
char[] sChars = s.toCharArray();
char[] tChars = t.toCharArray();
Arrays.sort(sChars);
Arrays.sort(tChars);
return Arrays.equals(sChars,tChars);
解法二:
把字符串转化为字符数组,然后遍历字符数组把每个字符为key,字符出现的次数为value存储到map结构中,然后遍历另一个字符数组时,把相同的字符都移除,最后返回时map为空返回true,不为空时则返回false。
Map<Character,Integer> map = new HashMap<>();
for(char ch : s.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1);
}
for(char ch : t.toCharArray()){
Integer count = map.get(ch);
if(count == null){
return false;
}else if(count > 1){
map.put(ch,count-1);
}else{
map.remove(ch);
}
}
return map.isEmpty();
- 要遍历字符串的话可以转换成字符数组再进行遍历
- map.getOrDefault(ch,0)存在这个key时就用这个key对应的value,否则就用默认的0
LeetCode704:二分查找
解法一:把left设置为0,right设置为num.length-1,mid取值(right-left)/ 2,做while循环left<=right时移动相应的指针,当nums[mid]==target时,把mid返回。
class Solution {
public int search(int[] nums, int target) {
//左闭右闭区间
//避免当target小于nums[0] nums[nums.length - 1]时多次循环运算
if(target < nums[0] || target > nums[nums.length - 1]){
return -1;
}
int left = 0,right = nums.length -1;
while(left <= right){
int mid = left +((right - left)>>1);
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
left=mid + 1;
}else if(nums[mid]>target){
right=mid - 1;
}
}
return -1;
//左闭右开区间
int left = 0,right=nums.length;
while(left<right){
int mid = left + ((right-left)>>1);
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
left=mid + 1;
}else if(nums[mid]>target){
right=mid;
}
}
return -1;
}
}
- left + ((right -left) >> 1) == (left + right) /2
LeetCode733:图像渲染
解法一:
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int oldColor = image[sr][sc];
DFS(image,sr,sc,newColor,oldColor);
return image;
}
public void DFS(int[][] image,int x,int y,int newColor,int oldColor){
if(x < 0 || x >= image.length || y < 0 || y >= image[0].length) {
return;
}
if(image[x][y] != oldColor || image[x][y] == newColor){
return;
}
image[x][y] = newColor;
DFS(image, x - 1, y,newColor,oldColor);
DFS(image, x + 1, y,newColor,oldColor);
DFS(image, x, y - 1,newColor,oldColor);
DFS(image, x, y + 1,newColor,oldColor);
}
}
LeetCode53:最大子数组和
class Solution {
public int maxSubArray(int[] nums) {
int res =nums[0];
int sum = 0;
for(int num : nums){
if(sum >0){
sum=sum+num;
}else{
sum=num;
}
res = Math.max(res,sum);
}
return res;
}
}
LeetCode235:二叉搜索树的最近公共祖先
解法一:解决树的方法用递归
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//先遍历找到p和q的节点位置,然后找出他们的公共祖先
if(p.val==root.val){
return p;
}
if(q.val==root.val){
return q;
}
if(p.val>root.val && q.val>root.val){
return lowestCommonAncestor(root.right,p,q);
}else if(p.val<root.val && q.val < root.val){
return lowestCommonAncestor(root.left,p,q);
}else{
return root;
}
}
}
- 二叉搜索树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
- 解决树的问题基本都要用递归
LeetCode110:平衡二叉树
解法一:
- 找终止条件:什么时候递归到头了?此题自然是root为空的时候,空树当然是平衡的。
- 思考返回值,每一级递归应该向上返回什么信息?参考我代码中的注释。
- 单步操作应该怎么写?因为递归就是大量的调用自身的重复操作,因此从宏观上考虑,只用想想单步怎么写就行了,左树和右树应该看成一个整体,即此时树一共三个节点:root,root.left,root.right。
class Solution {
public boolean isBalanced(TreeNode root) {
return isBST(root).isB;
}
//参考递归套路第二步:思考返回值是什么
//一棵树是BST等价于它的左、右俩子树都是BST且俩子树高度差不超过1
//因此我认为返回值应该包含当前树是否是BST和当前树的高度这两个消息
private class ReturnNode{
boolean isB;
int depth;
public ReturnNode(int depth,boolean isB){
this.isB = isB;
this.depth = depth;
}
}
//参考递归套路第三部:描述单次执行过程是怎么样的
//这里的单次执行过程具体如下:
//是否终止?->没终止的话,判断是否满足不平衡的三个条件->返回值
public ReturnNode isBST(TreeNode root){
if(root == null){
return new ReturnNode(0,true);
}
//不平衡的情况有3种:左树不平衡、右树不平衡、左树和右树差的绝对值大于1
ReturnNode left = isBST(root.left);
ReturnNode right = isBST(root.right);
if(left.isB == false || right.isB == false){
return new ReturnNode(0,false);
}
if(Math.abs(left.depth - right.depth) > 1){
return new ReturnNode(0,false);
}
//不满足上面3种情况,说明平衡了,树的深度为左右俩子树最大深度+1
return new ReturnNode(Math.max(left.depth,right.depth)+1,true);
}
}
- 平衡二叉树:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。高度:从叶子节点开始往上算。
LeetCode141:环形链表
解法一:核心思想:两个指针,一个一次走一步,一个一次走两步,如果走的快的出现在走的慢的后面,则有环
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null){
return false;
}
ListNode p = head;
ListNode q = head;
while(q!=null){
p = p.next;
q = q.next;
if(q == null){
return false;
}
q = q.next;
if(q == null){
return false;
}
if(q == p || q.next == p){
return true;
}
}
return false;
}
}