leetcode刷题笔记[Easy26-43题]

  • Eg136 只出现一次的数字 (新鲜)
    // 用异或操作解决问题,很新鲜
class Solution {
    public int singleNumber(int[] nums) {
    	int result = 0;
    	for (int i = 0; i < nums.length; i++)
    		result ^= nums[i];
    	return  result;
    }
}
  • Eg107. 二叉树的层次遍历
    //①Java的Linklist<>代表链表,继承List类,
    //指定链表元素只能是List列表,List代表列表List的元素只能是Integer
    //LinkedList<List> 是 List<List>的子类
    //②队列是一种特殊的线性表
    //LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。
    //Queue的常见方法:1)queue.poll():获取并移除队首,如果为空,返回null;
    //2)queue.remove():获取并移除队首,如果为空,返回异常;
    //3)queue.peek():获取队首元素,如果为空,返回null;
    //4)queue.element():获取队首元素,如果为空,返回异常;
    //5)queue.offer():插入元素,若成功返回true,否则返回false;
    //6)queue.add():插入元素,若不成功,抛出异常
    //7)queue.size():求队列元素总数
    //③List是抽象类,在创建的时候要说明是创建ArrayList(数组)、LinkedList(链表)
    //④链表LinkedList的两种插入方法:1)LinkedList.addFirst();2)LinkedList.addLast()
    //⑤Queue、LinkedList、ArrayList都是链表,所以在创建的时候不需要声明长度

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        //链表lli存放题目要求的元素
        LinkedList<List<Integer>> lli = new LinkedList<>();
        //注意:不能return null
        if (root == null)  return lli;
        //队列queue用来遍历树
        Queue<TreeNode> queue = new LinkedList<>();
        //数组valarr用来存放每层元素
        List<Integer> valarr = new ArrayList();
        //结点ptr存放出队结点
        TreeNode ptr;
        //lvllen存放每层的结点总数,count存放该层已经出队列的结点数
        int lvllen = 1, count = 0; 

        queue.add(root);
        while (!queue.isEmpty()) {
            //出队
            ptr = queue.poll();
            count++;
            valarr.add(ptr.val);
            if (ptr.left != null) 
                queue.add(ptr.left);
            if (ptr.right != null)
                queue.add(ptr.right);
            //每层最后一个结点出队列后,重新set
            if(count == lvllen) {
                lli.addFirst(valarr);
                //⑥由于上文已经定义了valarr的类型,此处重新申请内存时不需要再声明类型
                valarr = new ArrayList();
                count = 0;
                lvllen = queue.size();
            }
        }
        return lli;
    }
}
  • Eg108.将有序数组转为二叉树
    //思路:由于题意是高度平衡二叉树,且输入数组nums是递增数列,所以正中间是root
    //左右两边分别是左右子树。题意又说,一个序列可以是某个平衡二叉树,所以我们
    //可以将一个序列转化成左右子树结点个数相差1个的树,即左右子序列个数相差1个
    //所以m = l + (r-l)/2 可以用来解决问题。由于/运算是向下取的,所以(r-l)/2表示正中间或偏左
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public TreeNode sort
class Solution {
    //思路:由于题意是高度平衡二叉树,且输入数组nums是递增数列,所以正中间是root
    //左右两边分别是左右子树。题意又说,一个序列可以是某个平衡二叉树,所以我们
    //可以将一个序列转化成左右子树结点个数相差1个的树,即左右子序列个数相差1个
    //所以m = l + (r-l)/2 可以用来解决问题。由于/运算是向下取的,所以(r-l)/2表示正中间或偏左
    public TreeNode sortedArrayToBST(int[] nums) {
        return nums == null ? null : buildTree(nums, 0, nums.length-1);
    }

    public TreeNode buildTree(int[] nums, int l, int r) {
        if (l > r)  return null;
        TreeNode root = new TreeNode();
        //由于/运算是向下取的,所以(r-l)/2表示正中间或偏左
        int m = l + (r-l)/2;
        root.val = nums[m];
        root.left = buildTree(nums, l, m-1);
        root.right = buildTree(nums, m+1, r);
        return root;
    }
}
  • Eg110. 平衡二叉树
    //解题的关键:如果左右子树已经是不平衡树,逐渐地往上层传递-1;
    //简单情况下可以用三目运算符,复杂情况下最好不要用
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null)   return true;   
        int leftheight = getTreeHeight(root.left);
        int rightheight = getTreeHeight(root.right);
        if (leftheight == -1 || rightheight == -1)    
            return false;
        return  Math.abs(leftheight - rightheight) > 1 ? false : true;
    }


    public int getTreeHeight(TreeNode root) {
        if (root == null)   return 0;
        int leftheight = getTreeHeight(root.left);
        int rightheight = getTreeHeight(root.right);

        //如果子树开始不平衡
        if (Math.abs(leftheight - rightheight) > 1)   return -1;
            
        //如果某个结点的孩子已经是不平衡树,一直往上传递,该边的子树不平衡
        if (leftheight == -1 || rightheight == -1)   return -1;

        return  1 + Math.max(leftheight,rightheight);
    }
}
  • Eg111. 二叉树的最小深度:求二叉树的深度的变形
  • 递归求二叉树的深度,只要知道左子树的深度,跟右子树的深度即可
class Solution {
    public int minDepth(TreeNode root) {
        if (root == null)   return 0;
        int leftheight = minDepth(root.left);
        int rightheight = minDepth(root.right);
        //只有右子树
        if (leftheight == 0 && rightheight != 0)
            return 1 + rightheight;
        //只有左子树
        else if (rightheight == 0 && leftheight != 0)
            return 1 + leftheight;
        //均有左右子树或者均无左右子树
        else 
            return 1 + Math.min(leftheight, rightheight);
    }
}
  • Eg112.路径总和
    //思路:递归解决是否存在路径问题:递归传递剩余差
    //如果当前结点是叶子结点,且结点值等于剩余差,即说明有路径
    //如果存在路径,即指针传递到空节点,且空节点的父亲是叶子结点
    //我们不能仅仅用一个hasPathSum(root, sum)函数来实现递归,
    //1)最大根节点为null与子树为null不同。若测试用例为root = null, sum = 0,返回的应该是false;
    //2)一定要判断是从根节点到叶子结点,而不能是“存在子路径”。若到了null子结点,且sum=0,但其父结点不是子结点,仍应返回false
    //3)要考虑结点值可正可负
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        //思路:递归解决是否存在路径问题:递归传递剩余差
        //如果当前结点是叶子结点,且结点值等于剩余差,即说明有路径
        //如果存在路径,即指针传递到空节点,且空节点的父亲是叶子结点
        if(root == null)    return false;
        boolean leftflag = false, rightflag = false;
        int temp = sum-root.val;

        //我们不能仅仅用一个hasPathSum(root, sum)函数来实现递归,
        //1)最大根节点为null与子树为null不同。若测试用例为root = null, sum = 0,返回的应该是false;
        //2)一定要判断是从根节点到叶子结点,而不能是“存在子路径”。若到了null子结点,且sum=0,但其父结点不是子结点,仍应返回false
        //如果左子树有路径
        leftflag = hasSubPathSum(root, root.left, sum-root.val);
        //如果右子树有路径
        rightflag = hasSubPathSum(root, root.right, sum-root.val);
        
        //如果左子树有路径或者右子树有路径,说明该树有路径
        return leftflag || rightflag;
    }
    public static boolean hasSubPathSum(TreeNode parent, TreeNode root, int sum) {
        if (root == null)  {
            if(sum == 0 && parent != null && parent.left == null && parent.right == null)
                return true;
            else
                return false;
        }

        boolean leftflag = false, rightflag = false;
        leftflag = hasSubPathSum(root, root.left, sum-root.val);
        rightflag = hasSubPathSum(root, root.right, sum-root.val);
        return leftflag || rightflag;
    }
}

方法二:

class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null)    return false;
        if (root.val == sum) {
            if (root.left == null && root.right == null)
                return true;
        }

        boolean leftflag = false, rightflag = false;

        leftflag = hasPathSum(root.left, sum-root.val);
        rightflag = hasPathSum(root.right, sum-root.val);
        
        return leftflag || rightflag;
    }
}
  • Eg118 杨辉三角
    //①C/Java中function(int[] arr),是引用传递;
    //如果想要值传递,可在子函数里面用int[] b =Arrays.cpoyOf(arr,length);
    //②Java数组用ArrayList,遍历数组用ArrayList.get()
    //③Java ArrayList作为参数传的是值传递,LinkedList才是地址传递;
    //④Java求链表的长度用LinkedList.size()
    //⑤Java中链表的重新赋值用LinkedList.set(index,value)
class Solution {
    public List<List<Integer>> generate(int numRows) {
        LinkedList<List<Integer>>  lld = new LinkedList<List<Integer>>();
        if(numRows == 0)    return lld;
        List<Integer> l1 = new ArrayList<>();
        l1.add(1);
        lld.addLast(l1);
        if (numRows == 1)   return lld;
        List<Integer> l2 = new ArrayList<>();
        l2.add(1);
        l2.add(1);
        lld.addLast(l2);
        if (numRows == 2)   return lld;
       
        LinkedList<Integer> movarr = new LinkedList<>();
        movarr.add(1);
        movarr.add(1);

        for (int circnt = 2; circnt < numRows; circnt++) 
            generateYang(lld, movarr);
    
        return lld;
    }


    public static void generateYang (LinkedList<List<Integer>> lld, LinkedList<Integer> movarr) {
        LinkedList<Integer> lvl = new LinkedList<>();
        lvl.add(1);

        for(int i=0, j = 1; j < movarr.size(); i++, j++) {
            int temp = movarr.get(i) + movarr.get(j);
            lvl.add(temp);
        }
        lvl.add(1);
        lld.add(lvl);
    
        //movarr前半部分重新赋值
        for (int i = 0; i < movarr.size(); i++)
            movarr.set(i,lvl.get(i));
        //movarr后半部分添加
        for (int i = movarr.size(); i < lvl.size();i++)
            movarr.add(lvl.get(i));
    }
}

方法二:
//杨辉三角的性质:①第i行的元素个数为i个;②第i行两端元素为1,中间元素是第i-1行元素的和
//①Java中可扩展数组列表ArrayList(), 不会产生累赘元素;不可扩展数组int[]
//②拷贝ArrayList需要两个参数 pre = Arrays.copyOf(cur,j+1);一个是拷贝对象,一个是拷贝长度

class Solution {
    public List<List<Integer>> generate(int numRows) {
        //杨辉三角的性质:①第i行的元素个数为i个;②第i行两端元素为1,中间元素是第i-1行元素的和
        List<List<Integer>> list = new ArrayList<>();
        int[] pre = new int[numRows], cur = new int[numRows];
        for (int j = 1; j <= numRows; j ++) {
            //①Java中可扩展数组列表ArrayList(), 不会产生累赘元素;不可扩展数组int[]
            List<Integer> subList = new ArrayList<Integer>();

            for (int i = 0; i < j; i++) {
                //两端元素为1
                if (i == 0 || i == j) 
                    cur[i] = 1;
                else 
                    cur[i] = pre[i-1] + pre[i];
                //由于sublist是可扩展的数组,不会产生累赘元素
                subList.add(cur[i]);
            }
            list.add(subList);
            pre = Arrays.copyOf(cur,j+1);
        }
        return list;
    }
}
  • Eg122.买卖股票的最佳时机II (与最大子串那道题相结合)
    动态规划的思想 我还是没有总结出动态规划的特性。
    如果要获得的总利润最大,就要让每一步获得的利润最大。而每一步的利润最大就是只要第二天比第一天有收益就售出。乍眼看这会造成短视行为。但是,假设连续三天都涨,第二天售出,立刻第二天买入,第三天售出。这与第一天买入,第三天售出是一样的。
class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0 || prices.length == 1)
            return 0;
        int maxprofit = 0;
        for (int i = 0; i < prices.length-1; i++) {
            if (prices[i+1] > prices[i])
                maxprofit += prices[i+1] - prices[i];
        }
        return maxprofit;
    }
}
  • Eg155 最小栈
    //思路:栈顶始终为当前栈内最小的元素
    //熟悉使用栈Stack的方法
    //1)stack.empty();
    //2)stack.add();
    //3)stack.peek(); 仅获取栈顶元素
    //4)stack.get(index); 获取下标为index的元素
    //全局变量用修饰词 加个 public static
class MinStack {

    public static Stack stack;    
    /** 构造器 */
    public MinStack() {
        stack = new Stack<Integer>();
    }
    
    public void push(int x) {
        if (stack.empty()) {
            stack.add(x);
            stack.add(x);
        }
        else {
            int topelement = stack.peek();
            //int topelement = stack.peek();
            //将最新元素压入栈
            stack.add(x);
            //当前栈内的最小元素压入栈
            if (x > topelement)
                stack.add(topelement);
            else
                stack.add(x);
        }
    }
    
    public void pop() {
        stack.pop();
        stack.pop();
    }
    
    public int top() {
        return stack.get(stack.size()-2);
    } 
    public int getMin() {
        return stack.get(stack.size()-1);
    }
}
  • Eg160 相交链表(妙!!!重做!!)
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null)     return null;
        ListNode atr = headA, btr = headB;
        int lenA = 0, lenB = 0;
        while (atr != null) {
            atr = atr.next;
            lenA++;
        }    
        atr = headB;
        while (btr != null) {
            btr = btr.next;
            lenB++;
        }    
        btr = headA;

        //走同样的步数
        if (lenA > lenB)
            for (int i = 0 ; i < lenA - lenB; i++)
                btr = btr.next;
        else
            for (int i = 0 ; i < lenB - lenA; i++)
                atr = atr.next;
            
        while (atr != null) {
            if (atr == btr)
                return atr;
            else {
                atr = atr.next;
                btr = btr.next;
            }
        }
        return null;

    }
}
  • Eg167 两数之和
    //解题思路关键:注意到所给的数组numbers是升序排序
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] res = new int[2];
        int left = 0, right = numbers.length-1;
        while (left < right) {
            if (numbers[left] + numbers[right] == target) {
                res[0] = left+1;
                res[1] = right+1;
            }
            //两数之和过大,则要缩小,故右游标左行
            if (numbers[left] + numbers[right] > target)
                right--;
            //两数之和过小,则要放大,故左游标右行
            else 
                left++;
        }
        return res;
    }
}
  • Eg168 Excel表列名称
    //思路:10进制转26进制,参照10进制转2进制(除2取余法)
    //这里1-A … 26-Z; 在26进制中,从0开始无26对应的字符,且此处Excel的26进制表示的是(0,无穷),10进制表示[0,无穷]
    //即在每个进制位上(个十百千万) 对于每一个10进制的数,应先将其减1再去数字-字符表找对照
    //Eg:26
    26 + 26 =>step1: 26
    26 + 25(Z) => 25
    26 (Z)
    //我们不要有个switch…case 来存储数字-字符表,只需要在“A”的基础上添加即可***
    //①Java的StringBuilder与String的区别:
    //1)String每次赋值都是指向新的对象;2)StringBuilder每次赋值是在自身基础进行修改;
    //当程序中需要大量的对某个字符串进行操作时,应该考虑应用StringBuilder类处理该字符串
    //②Java的StringBuilder若要转化为String,需要StringBuilder.toString()操作
class Solution {
    public String convertToTitle(int n) {

    	StringBuilder sb = new StringBuilder();
    	while(n > 0) {
    		n--;
    		sb.append((char)(n%26 + 'A'));
    		n /= 26;
    	}
    	String result = sb.reverse().toString();
    	return result;
    }
}
  • Eg169 多数元素
    =================================================
    回顾快速排序算法
    //rtr一直往左走,直到所指元素值小于pivot值;跳出循环时,rtr调到ltr上
    //关键:一定要是>= 或者 <= (即包括=)时,移动。否则在中途碰到与pivot值相等的元素,游标不会移动
public void QuickSort(int[] nums, int left, int right) {
    	if (left >= right)	return; 
		int pivot = nums[left], temp;
		int ltr = left, rtr = right;
		while (ltr < rtr) {
			//rtr一直往左走,直到所指元素值小于pivot值;跳出循环时,rtr调到ltr上
			while (nums[rtr] > pivot && ltr < rtr)
				rtr--;		
			//ltr一直往右走,直到所指元素值大于pivot值
			while (nums[ltr] < pivot && ltr < rtr)
				ltr++;
			//如果循环并未结束
			if (ltr < rtr) {
				temp = nums[rtr];
				nums[rtr] = nums[ltr];
				nums[ltr] = temp;
			}
		}
		//跳出循环时,[left+1, ltr]均为小于pivot值,[rtr+1,right]均为大于pivot的值
		nums[left] = nums[rtr];
		nums[rtr] = pivot;
		QuickSort(nums, left, rtr-1);
		QuickSort(nums, rtr+1, right);
    }

方法一:先排序

    	QuickSort(nums, 0, nums.length-1);
    	//或者使用Java现成的排序api
    	//Arrays.sort(nums);
		//return nums[nums.length / 2];
		
    	int count = 1, curmeta = nums[0];
    	for (int i = 1; i < nums.length; i++) {	
    		if (nums[i] == curmeta) {
    			count++;
    			if (count > (nums.length/2))	
    			return curmeta;
    		}
    		else {
    			curmeta = nums[i];
    			count = 1;
    		}
    	}
    	return nums[0];

方法二:哈希表
//Java HashMap类的常用使用
//1)声明变量类型:HashMap<K,V>
//2)添加映射元素(1个映射元素叫entry):HashMap.put(K,V)
//3)判断是否存在某个哈希映射元素:HashMap.containsKey(K)
//4)根据V获取K:HashMap.getKey(V)
//5)根据K获取V:HashMap.getValue(K)
//6)遍历哈希表:用for-each方法
//for(Map.Entry<K,V> entry :hash.entryset())

class Solution {
    public int majorityElement(int[] nums) {
        HashMap<Integer,Integer> hash = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (!hash.containsKey(nums[i] ))
                hash.put(nums[i],1);
            else{
                int count = hash.get(nums[i]);
                hash.put(nums[i],count+1);
            }
        }
        for (Map.Entry<Integer,Integer> entry : hash.entrySet()) {
            if (entry.getValue() > (nums.length / 2))
                return entry.getKey();
        }
        return -1;
    }
}
  • Eg172阶乘后的零(重做)
    尝试过先求出阶乘再除10求阶乘后的0,问题是Int只能表示1亿以下的数,即使是long对于130!也是不够装
    力扣评论思路:

首先题目的意思是末尾有几个0
比如6! = 【1* 2* 3* 4* 5* 6】
其中只有25末尾才有0,所以就可以抛去其他数据 专门看2 5 以及其倍数 毕竟 4 * 25末尾也是0
比如10! = 【2
456810】
其中 4能拆成22 10能拆成25
所以10! = 【2*(22)5(23)(222)(25)】
一个2和一个5配对 就产生一个0 所以10!末尾2个0
转头一想 2肯定比5多 所以只数5的个数就行了
假若N=31 31里能凑10的5为[5, 2
5, 35, 45, 25, 6*5] 其中 25还能拆为 52
所以 里面的5的个数为 int(31/(5
1)) + int(31/(52))
所以 只要先找个一个 5
x < n 的x的最大数 然后按上面循环加起来

class Solution {
    public int trailingZeroes(int n) {
        int maxmi = 1, cntOfZeroes = 0;
        
        while(Math.pow(5,maxmi) <= n)
            maxmi++;
        maxmi--;
        for (int i = 1; i <= maxmi; i++)
            cntOfZeroes += n / Math.pow(5,i);
        return cntOfZeroes;
    }
}
  • Eg189 旋转数组 (妙)
    方法一:时间复杂度O(kn),空间复杂度O(1),即外循环循环k次,内循环循环n-1次,每次外循环结果是数组向右移动1位

方法二:(妙) 重做!!!
1)将所有数组逆转
2)将前面k个元素逆转
3)将后面n-k个元素逆转

class Solution {
    public void rotate(int[] nums, int k) {
        k %= nums.length;
        if (k > 0) {
            inverseNumsArray(nums, 0, nums.length-1);
            inverseNumsArray(nums, 0, k-1);
            inverseNumsArray(nums, k, nums.length-1);
        } 
    }
    public void inverseNumsArray(int[] nums, int start, int end) {
        int temp;
        for (int i = start, j = end ; i < j ; i++, j--) {
            temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章