Day1|你就像一道二分查找
Leetcode704.二分查找
使用前提:有序数组
本质:根据是否满足题目条件来缩小答案的区间
fast
数组中移除元素并不容易! | LeetCode:27. 移除元素哔哩哔哩bilibili
Day2|977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II
滑动窗口的本质上是满足了单调性,when sum >= target,左指针右移,再检查此区间内是否仍>=target,以此来找到最小区间
螺旋矩阵:offset的意义在于结束一圈后,起始位置向后,结束位置向前移
Day3|移除链表|设计链表|反转链表
移除链表元素
1.要把哪个元素排除出元素,只需要使得没有指向它的指针,如果cur指向2那么只能更改2的next指针
2.链表首先要想好指针式怎么移动的,是否会访问null
设计链表
自己打一下好了
//细节点还是比较多的 class MyLinkedList { int size; ListNode head; public MyLinkedList() { size = 0; head = new ListNode(0); } public int get(int index) { if(index<0||index>=size){ return -1; } ListNode cur = head;//cur指向的是虚拟头节点 for(int i = 0;i<=index;i++) {//因为设置了虚拟头结点,就需要跳两次 cur = cur.next; } return cur.val; } public void addAtHead(int val) { addAtIndex(0,val); } public void addAtTail(int val) { addAtIndex(size,val); } public void addAtIndex(int index, int val) { if(index>size){ return ; } if(index<0){ index = 0; } size++; ListNode pre = head; for(int i = 0;i<index;i++) { pre = pre.next; } ListNode newNode = new ListNode(val); newNode.next = pre.next; pre.next = newNode; } public void deleteAtIndex(int index) { if(index<0||index>=size){ return; } size--; ListNode pre = head; //同样也是找前驱 for(int i = 0;i<index;i++){ pre = pre.next; } pre.next = pre.next.next; } } /** * Your MyLinkedList object will be instantiated and called as such: * MyLinkedList obj = new MyLinkedList(); * int param_1 = obj.get(index); * obj.addAtHead(val); * obj.addAtTail(val); * obj.addAtIndex(index,val); * obj.deleteAtIndex(index); */
反转链表
DAY4| 24. 两两交换链表中的节点 |19.删除链表的倒数第N个节点 |面试题 02.07. 链表相交 |142.环形链表II
两两交换链表中的结点
while(pre.next!=null && pre.next.next != null){ //奇数结点最后一个不需要交换 }
Day6| 242.有效的字母异位词 |349两个数组的交集 |202快乐数|1.两数之和
两个数组的交集
class Solution { public int[] intersection(int[] nums1, int[] nums2) { if(nums1 == null || nums1.length == 0 ||nums2 == null || nums2.length == 0){ return new int[0]; } Set<Integer> set1 = new HashSet<>() Set<Integer> resSet = new HashSet<>(); //遍历数组1 for(int i:nums1){ set1.add(i);//可以去重 } for(int i:nums2){ if(set1.contains(i)){ resSet.add(i);//如果元素i在nums1 and nums2 都有,就加入 } } return resSet.stream().mapToInt(x->x).toArray(); } }
快乐数
class Solution { public boolean isHappy(int n) { int temp = getSum(n); Set<Integer> set = new HashSet<>(); while(temp!=1){ if(!set.contains(temp)){ //如果还不是快乐数,并且在快乐数的循环中还没有出现重复的值 set.add(temp); //加入此次探索中出现的数 } else{//如果出现重复的值,那就说明陷入了无限循环 return false; } temp = getSum(temp); return true; } } public int getSum(int n){ int sum = 0; while(n!=0){ sum += (int)Math.pow(n%10,2); n = n/10;//退位 } return sum; } }
两数之和
class Solution { public int[] twoSum(int[] nums, int target) { Map<Integer,Integer> map = new HashMap<>(); int[] res = new int[2]; for(int i = 0;i<nums.length;i++){ int temp = target-nums[i]; if(map.containsKey(temp)){ res[0] = map.get(temp); res[1] = i; break;//找到了就直接结束遍历搜索了 } map.put(nums[i],i); } return res; } }
Day7| 454.四数相加II |384赎金信 |15.三数之和 |18四数之和
四数之和
class Solution { public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { int res= 0; HashMap<Integer,Integer> map = new HashMap<>(); for(int i:nums1){ for(int j:nums2){ int sum = i+j; map.put(sum,map.getOrDefault(sum,0)+1); //如果找到了,就会返回sum的次数 //map.put(sum,value),value是sum出现的次数 } } for(int i:nums3){ for(int j:nums4){ int sum = i+j; res += map.getOrDefault(-sum,0); } } return res; } }
赎金信
class Solution { public boolean canConstruct(String ransomNote, String magazine) { int[] a = new int[26]; for(int i = 0;i<ransomNote.length();i++){ a[ransomNote.charAt(i)-'a']++; }//将ransomNote中的字母的数量存储起来 for(int i = 0;i<magazine.length();i++){ if(a[magazine.charAt(i)-'a']==0) continue; a[magazine.charAt(i)-'a']--; //遍历magazine中所有的字母,如果数组不为0,说明ransmNote同样具备,这个时候就可以对应消除掉 } for(int i = 0 ;i<26;i++){ if(a[i]!=0) return false; } return true; } }
三数之和
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new ArrayList<>(); Arrays.sort(nums); for(int i = 0;i<nums.length;i++){ if(nums[i]>0){ return result; } if(i>0&&nums[i] == nums[i-1]){ continue; } int left = i+1; int right = nums.length-1; while(right>left){ int sum = nums[i]+nums[left]+nums[right]; if(sum>0){ right--; }else if(sum<0){ left++; }else{ result.add(Arrays.asList(nums[i],nums[left],nums[right])); //前面都是对a去重,再找到一个三元组后,对b和c进行去重 while(right>left && nums[right] == nums[right-1]) right--; while(right>left && nums[left] == nums[left+1]) left++; right--; left++; } } } return result; } }
四数之和
class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> res = new ArrayList<>(); Arrays.sort(nums); for(int k = 0;k<nums.length;k++){ if(nums[k]>target && target>0) break; //因为是从小到大排序,如果一个数已经大于target了,那么就没有必要往后面进行探索了 if(k>0&&nums[k]==nums[k-1]) continue; //去重 //与三重还是有联系的,都是先确定初始位置 for(int i = k+1;i<nums.length;i++){ if(i>k+1 && nums[i] == nums[i-1]) continue;//这里也是去重操作 int temp = nums[k]+nums[i]; int left = i+1; int right = nums.length-1; while(left<right){ long sum = (long)nums[left] + nums[right] + temp; if(sum>target){ right--; } else if(sum<target){ left++; } else{ res.add(Arrays.asList(nums[k],nums[i],nums[left],nums[right])); //每次确定一个四重组合,又要对c,d去重 while(left<right && nums[left] == nums[left+1]) left++; while(left<right&&nums[right] == nums[right-1]) right--; left++; right--; //去完重之后,还是需要移动,因为前面的代码并没有移动 } } } } return res; } }
6.25 还是想要复习一下二叉树
Java中TreeNode通常是由自己定义的类实现的,用于表示二叉树的节点。具体来说,可以将TreeNode定义为一个包含value、left子节点和right子节点三个成员变量的类。其中value可以是任何类型,left和right则是指向另外两个TreeNode对象的引用。
下面是一个简单的样例,用于展示TreeNode的定义和使用:
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public class Solution { public static void main(String[] args) { // 创建一棵二叉树 TreeNode root = new TreeNode(1); root.left = new TreeNode(2); root.right = new TreeNode(3); root.left.left = new TreeNode(4); root.left.right = new TreeNode(5); // 遍历二叉树 System.out.println("Preorder traversal: "); preorderTraversal(root); System.out.println("\nInorder traversal: "); inorderTraversal(root); System.out.println("\nPostorder traversal: "); postorderTraversal(root); } // 前序遍历 public static void preorderTraversal(TreeNode root) { if (root == null) { return; } System.out.print(root.val + " "); preorderTraversal(root.left); preorderTraversal(root.right); } // 中序遍历 public static void inorderTraversal(TreeNode root) { if (root == null) { return; } inorderTraversal(root.left); System.out.print(root.val + " "); inorderTraversal(root.right); } // 后序遍历 public static void postorderTraversal(TreeNode root) { if (root == null) { return; } postorderTraversal(root.left); postorderTraversal(root.right); System.out.print(root.val + " "); } }
在这个示例中,我们定义了一个TreeNode类用于表示二叉树的节点,然后创建了一棵二叉树。最后,我们使用前序、中序和后序遍历算法打印出了这棵二叉树的节点值。
中序遍历
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new LinkedList<>(); Stack<TreeNode> st = new Stack<>(); if(root!=null){ st.push(root); } while(!st.isEmpty()){ TreeNode node = st.peek(); if(node!=null){ st.pop();//node已经指向中顶元素了 if(node.right!=null){ st.push(node.right); } st.push(node); st.push(null); if(node.left!=null){ st.push(node.left); }//如果这一步没有了,null的作用就正式开始,后面就会将stack中的值依次放入res数组中 } else{//到了这一步就是到了最左子节点 st.pop();//将null去去除 node = st.peek(); st.pop();//每次取了peek的值都是要pop掉的 res.add(node.val); } } return res; } }
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new LinkedList<>(); Stack<TreeNode> st = new Stack<>(); if(root!=null){ st.push(root); } while(!st.isEmpty()){ TreeNode node = st.peek(); if(node!=null) // 就开始右中左的入栈顺序 { st.pop();//每次peek一个都要即时pop() if(node.right!=null){ st.push(node.right); } st.push(node); st.push(null); if(node.left!=null){ st.push(node.left); } } else{ st.pop(); node = st.peek(); res.add(node.val); st.pop(); } } return res; } }
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); if(root == null){ return res; } Stack<TreeNode> st = new Stack<>(); //注意在开始的时候是不需要加root的 TreeNode cur = root; while(cur!=null || !st.isEmpty()){ // cur !=nulll 是为了让我们顺利遍历到左子树最左子节点 // st.isEmpty() 是为了将stack存到res中去的 if(cur !=null){//cur承担遍历到最左子节点的作用,最初的结点也算是一个左节点 st.push(cur); cur = cur.left; } else{ cur = st.pop();//cur承担了最后栈转换到res的中转站 res.add(cur.val); cur = cur.right; } } return res; } }
后序遍历
入栈顺序:中左右//代码是这个
出栈顺序:中右左
倒转:左右中
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); if(root == null){ return res; } Stack<TreeNode> st = new Stack<>(); st.push(root); while(!st.isEmpty()){ TreeNode cur = st.pop(); res.add(cur.val); if(cur.left!=null){ st.push(cur.left); } if(cur.right!=null){ st.push(cur.right); } } Collections.reverse(res); return res; } }
二叉树的层序遍历
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { private List<List<Integer>> resList = new ArrayList<>(); public List<List<Integer>> levelOrder(TreeNode root) { travelsal(root,0); return resList; } private void travelsal(TreeNode root,int deep) { //第一部先判断是否为叶子节点 if(root == null) return; //如果不是,则就是新的一层,需要加一层深度 deep++; //加了一层深度,也就意味着需要加一个List<>来储存这一层叶节点的值 //当然只有第一次,也就是最左边结点遍历的时候才会需要去加一个List<> if(resList.size()<deep){ List<Integer> temp = new ArrayList<>(); resList.add(temp); } //实际操作的时候,deep-1 才是当前层 resList.get(deep-1).add(root.val); travelsal(root.left,deep); travelsal(root.right,deep); } }
感觉层序遍历那里真的有点多了,没有必要,后面还是要过的
翻转二叉树
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public TreeNode invertTree(TreeNode root) { //递归写法 //1.确定终止条件 if(root == null){ return null; } //先交换左右孩子结点,然后反转右孩子结点 //然后反转左子树,反转右子树 //我们可以发现这两步其实就是从小看大 invertTree(root.left); invertTree(root.right); swap(root); return root; } private void swap(TreeNode node){ TreeNode temp = node.left; node.left = node.right; node.right = temp; } }
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public TreeNode invertTree(TreeNode root) { //迭代法就是从头到脚遍历 if(root == null) return null; Deque<TreeNode> que = new ArrayDeque<>(); que.offer(root); while(!que.isEmpty()){ int size = que.size(); for(int i = 0;i<size;i++){ TreeNode node = que.poll(); swap(node);//先将头节点的左右子树进行更换 if(node.left!=null) que.offer(node.left); if(node.right!=null) que.offer(node.right);//这里是按照队列的规矩办事 } } return root; } private void swap(TreeNode node){ TreeNode tmp = node.left; node.left = node.right; node.right = tmp; } }