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;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章