数组
常见操作
// 创建数组的常用操作:元素可以个数可以动态变化
ArrayList<Integer> = new ArrayList<>();
//添加:不用扩容 - O(1) / 需要扩容 - O(n)
.add()
//访问:O(1)
.get( int index)
//查找元素:O(n)
.contains( Object obj)
//删除:O(n)
.remove( Object obj)
//更新元素:O(1)
.set( int index , Object obj)
//数组大小
.size()
//数组排序:O( NlogN)
Collections.sort()
Collections.sort(arr,Collections.reverseOrder())
// 创建数组
int[] c = new int[3];
int[] a = {1,2,3};
int[] b = new int[]{1,2,3};
//数组排序
Arrays.sort( )
题目
-
485. 最大连续 1 的个数 - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public int findMaxConsecutiveOnes(int[] nums) { if(null == nums){ return 0; } //最大连续1的个数 int max = 0; //标志位:如果不为0,则说明上一个元素是1 + 当前已有的连续1个数 int temp = 0; for(int i = 0;i < nums.length;i++){ if(1 == nums[i]){ max++; }else{ max = max > temp ? max : temp; temp = 0; } } max = max > temp ? max : temp; return max; } }复杂度分析
- 时间复杂度:O(n)。n是数组的长度。需要遍历数组一次。
- 空间复杂度:O(1)。
-
283. 移动零 - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public void moveZeroes(int[] nums) { int head = 0,index = 0; //找到第一个0的位置 while(head < nums.length && 0 != nums[head]){ head++; index = head; } //数组存在非0元素 while(head < nums.length){ //当前元素为0 if(0 == nums[index]){ //寻找后面第一个非0元素的位置 while(head < nums.length && 0 == nums[head]){ head++; } //找到了 if(head < nums.length){ nums[index++] = nums[head]; nums[head++] = 0; }else{ //没找到:后面的元素全部都是0 return; } }else{ index++; } } } }复杂度分析
- 时间复杂度:O(n)。n是数组的长度。需要遍历数组一次。
- 空间复杂度:O(1)。
-
27. 移除元素 - 力扣(LeetCode) (leetcode-cn.com)
若要求非val元素保证顺序:可以利用上一题的解法(快慢指针),寻找下一个不是val的元素进行替代。但是此题没有要求顺序,那么也可以利用相对指针。
class Solution { public int removeElement(int[] nums, int val) { if(null == nums || nums.length == 0){ return 0; } int head = 0,tail = nums.length-1; // 1 遍历数组 while(head <= tail){ //2 是val if(nums[head] == val){ //2.1 从后往前找,不是val的元素 while(tail > head && nums[tail] == val){ tail--; } //2.1.1 没找到:当前元素和其后的元素都是val if(tail <= head){ return head; }else{//2.1.2 找到了 nums[head++] = nums[tail--]; } }else{//3 不是val,继续判断下一个元素 head ++; } } return head; } }
链表
常用操作
LinkedList<Integer> list = new LinkedLisr<>()
//加在尾部 O(1)
.add(Object obj)
.add(int index,Object obj)
//访问元素 O(n)
.indexOf(Object obj)
//更新元素
.set(int index,Object obj)
//删除元素 O(1)
.remove(int index)
//长度
.size()
题目
-
203. 移除链表元素 - 力扣(LeetCode) (leetcode-cn.com)
-
创建一个结点,它的下一个结点指向 head头节点
-
遍历链表,从新创建的结点开始,
-
如果下一个结点为val,利用循环往后寻找不是val的第一个结点
- 删除中间所有值是val的结点
- 移动链表,指向下一个结点
-
如果当前结点的下一个结点为val,那么移动链表,指向下一个结点
-
class Solution { public ListNode removeElements(ListNode head, int val) { if(null == head){ return head; } ListNode current = new ListNode(-1,head); ListNode dummy = current; while(null != current && null != current.next){ ListNode next = current.next; while(null != next && next.val == val){ next = next.next; } current.next = next; current = current.next; } return dummy.next; } } -
-
206. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)
//方法一: class Solution { public ListNode reverseList(ListNode head) { ListNode pre = null,next = null; ListNode current = head; while(null != current){ //改变指针指向 next = current.next; current.next = pre; //移动链表 pre = current; current = next; } return pre; } } //方法二: class Solution { public ListNode reverseList(ListNode head) { // 1 终止条件 if(null == head || null == head.next){ return head; } // 2 大问题的答案 ListNode r_head = reverseList(head.next); // 3 当前问题的解答 head.next.next = head; head.next = null; return r_head; } }
- 思考的时候多画图,可以清晰很多
- 边界情况考虑,看是否可以合并到一般情况
队列和栈
常用操作
| 常用操作 | Queue | Stack |
|---|---|---|
| 增加元素 | add(Object obj) | push(Object obj) |
| 获取元素 | peek() | peek() |
| 删除元素,并返回 | poll() | pop() |
| 大小 | size() | size() |
| 是否为空 【边遍历边判断】 | isEmpty() | isEmpty() |
操作
-
933. 最近的请求次数 - 力扣(LeetCode) (leetcode-cn.com)
class RecentCounter { //创建队列 Queue queue = new LinkedList<Integer>(); public RecentCounter() { } public int ping(int t) { this.queue.add(t); while(!queue.isEmpty()){ Integer element = (Integer)queue.peek(); if(t-3000 <= element){ return queue.size(); }else{ queue.poll(); } } return 0; } } -
20. 有效的括号 - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public boolean isValid(String s) { //定义多有括号对应关系 HashMap<Character,Character> map = new HashMap(); map.put('(',')'); map.put('[',']'); map.put('{','}'); //定义栈结构 Stack stack = new Stack<Character>(); //将所有字符入栈 for(int i = 0 ;i < s.length();i++){ char c = s.charAt(i); //如果是左括号,入栈 if(map.containsKey(c)){ stack.push(c); }else{ //如果是右括号,则出栈上一个元素 if(stack.isEmpty() || (c != map.get(stack.peek()))){ return false; }else{ stack.pop(); } } } if(!stack.isEmpty()){ return false; } return true; } } -
496. 下一个更大元素 I - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public int[] nextGreaterElement(int[] nums1, int[] nums2) { HashMap<Integer,Integer> map = new HashMap<>(); Stack<Integer> stack = new Stack(); //遍历nums2,找出所有元素对应的下一个最大值 for(int i = 0;i < nums2.length;i++){ if(stack.isEmpty()){ stack.push(nums2[i]); }else{ while(!stack.isEmpty() && stack.peek() < nums2[i]){ map.put(stack.pop(),nums2[i]); } stack.push(nums2[i]); } } while(!stack.isEmpty()){ map.put(stack.pop(),-1); } // 遍历 nums1 得到结果集 int[] res = new int[nums1.length]; for (int i = 0; i < nums1.length; i++) { res[i] = map.get(nums1[i]); } return res; } }
HashMap
常见操作
HashMap<Integer,Integer> map = new HashMap<>();
//添加元素
.put(1,1)
//更新元素(利用唯一性)
.put(1,3)
//删除元素
.remove(key)
//获取元素
.get(key)
//判断key是否存在
.containsKey()
//大小
.size()
//是否为空
.isEmpty()
题目
-
217. 存在重复元素 - 力扣(LeetCode) (leetcode-cn.com)
//方法一 class Solution { public boolean containsDuplicate(int[] nums) { HashSet<Integer> set = new HashSet<>(); for(int i = 0;i < nums.length;i++){ set.add(nums[i]); } if(nums.length == set.size()){ return false; } return true; } } //方法二 class Solution { public boolean containsDuplicate(int[] nums) { HashMap<Integer,Object> map = new HashMap<>(); for(int i = 0;i < nums.length;i++){ map.put(nums[i],null); } if(nums.length == map.size()){ return false; } return true; } } -
389. 找不同 - 力扣(LeetCode) (leetcode-cn.com)
//方法一 class Solution { public char findTheDifference(String s, String t) { HashMap<Character,Integer> map = new HashMap<>(); Character key; int value; for(int i = 0;i < s.length();i++){ key = s.charAt(i); //已经出现过的key if(!map.containsKey(key)){ map.put(key,1); }else{ value = map.get(key)+1; map.put(key,value); } } for(int i = 0;i < t.length();i++){ key = t.charAt(i); //map中有的key if(map.containsKey(key)){ value = map.get(key) - 1; if(value < 0){ return key; } map.put(key,value); }else{ //map中不存在的key return key; } } return t.charAt(t.length()-1); } } //方法二 class Solution { public char findTheDifference(String s, String t) { int result = 0; //利用异或运算 for(int i = 0;i < s.length();i++){ result ^= s.charAt(i); } for(int i = 0;i < t.length();i++){ result ^= t.charAt(i); } return (char)result; } }
【唯一性】
- 判断是否有重复元素:大小是否有变化
- 找不同
【利用异或运算】
- 提高运算效率
HashSet
常见操作
HashSet<Integer> set = new HashSet<>();
//添加元素
.ddd(1)
//删除元素
.remove(key)
//判断key是否存在
.contains( )
//大小
.size()
//是否为空
.isEmpty()
题目
-
705. 设计哈希集合 - 力扣(LeetCode) (leetcode-cn.com)
设计的时候要记得保证各种操作的时间复杂度
class MyHashSet { int [] arr = new int[1000009]; /** Initialize your data structure here. */ public MyHashSet() { } // void add(key) 向哈希集合中插入值 key public void add(int key) { this.arr[key] = 1; } public void remove(int key) { arr[key] = 0; } /** Returns true if this set contains the specified element */ public boolean contains(int key) { if(arr[key] == 1){ return true; }else{ return false; } } }
树
相关概念
- 完全二叉树:每一层的结点从左到右依次
- 满二叉树:每一层的结点数都达到最大值
- 深度 高度 层
二叉树的遍历
-
144. 二叉树的前序遍历 - 力扣(LeetCode) (leetcode-cn.com)
//方法一:利用栈,后进先出 class Solution { public List<Integer> preorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } TreeNode node; ArrayList<Integer> result = new ArrayList<>(); Stack<TreeNode> stack = new Stack<>(); //将头节点入栈, stack.push(root); while(!stack.isEmpty()){ //打印栈顶 node = stack.pop(); result.add(node.val); //让右左结点依次入栈(后进先出) if(null != node.right){ stack.push(node.right); } if(null != node.left){ stack.push(node.left); } } return result; } } //方法二:递归 class Solution { public List<Integer> preorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } List<Integer> result_left = preorderTraversal(root.left); List<Integer> result_right = preorderTraversal(root.right); ArrayList<Integer> result = new ArrayList<>(); result.add(root.val); result.addAll(result_left); result.addAll(result_right); return result; } } -
94. 二叉树的中序遍历 - 力扣(LeetCode) (leetcode-cn.com)
//方式一 class Solution { public List<Integer> inorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } //[最左所有的结点沿途的结点入栈] Stack<TreeNode> stack = new Stack<>(); while(null != root){ stack.push(root); root = root.left; } TreeNode node; ArrayList<Integer> result = new ArrayList<>(); while(!stack.isEmpty()){ //栈顶出栈 node = stack.pop(); result.add(node.val); //栈顶的右孩子入栈 if(null != node.right){ stack.push(node.right); node = node.right; //栈顶的右孩子入栈 [最左所有的结点沿途的结点]入栈 while(null != node.left){ node = node.left; stack.push(node); } } } return result; } } //方式二 class Solution { public List<Integer> inorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } List<Integer> result_left = inorderTraversal(root.left); List<Integer> result_right = inorderTraversal(root.right); ArrayList<Integer> result = new ArrayList<>(); result.addAll(result_left); result.add(root.val); result.addAll(result_right); return result; } } -
145. 二叉树的后序遍历 - 力扣(LeetCode) (leetcode-cn.com)
//方法一 class Solution { public List<Integer> postorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } //一开始和前序遍历是一致的:都是最左路径上的结点 Stack<TreeNode> stack = new Stack<>(); while(null != root){ stack.push(root); root = root.left; } //上一个结点时当前的结点的右节点,则当前结点打印 TreeNode pre = null; TreeNode current; ArrayList<Integer> result = new ArrayList<>(); while(!stack.isEmpty()){ current = stack.peek(); //如果是叶子结点 || 上一个结点是栈顶的右子节点 if(null == current.right || pre == current.right){ pre = stack.pop(); result.add(pre.val); }else{ current = current.right; stack.push(current); while(null != current.left){ current = current.left; stack.push(current); } } } return result; } } //方法二 class Solution { public List<Integer> postorderTraversal(TreeNode root) { if(null == root){ return new ArrayList<>(); } List<Integer> result_left = postorderTraversal(root.left); List<Integer> result_right = postorderTraversal(root.right); ArrayList<Integer> result = new ArrayList<>(); result.addAll(result_left); result.addAll(result_right); result.add(root.val); return result; } }
利用栈,单调栈 || 双栈,出栈的时机(打印)
堆
常见操作
//最小堆
PriorityQueue<Integer> minheap = new PriorityQueue<>();
//最大堆
PriorityQueue<Integer> maxheap = new PriorityQueue<>(Collections.reverseOrder());
//添加元素
.add() | .offer()
//获得堆顶元素
.peek()
//删除元素
.poll() | .remove()
//堆的大小
.size()
//堆是否为空
.isEmpty()
题目
-
215. 数组中的第K个最大元素 - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public int findKthLargest(int[] nums, int k) { if(nums.length < k){ return -1; } //创建最大堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder()); //添加元素 for(int i = 0;i < nums.length;i++){ maxHeap.add(nums[i]); } //通过获取第k个堆顶元素 for(int i = 1;i < k;i++){ maxHeap.poll(); } return maxHeap.peek(); } -
692. 前K个高频单词 - 力扣(LeetCode) (leetcode-cn.com)
class Solution { public List<String> topKFrequent(String[] words, int k) { HashMap<String,Integer> map = new HashMap<>(); //统计单词每个单词出现的顺序 int value = 0; for(int i = 0;i < words.length;i++){ if(!map.containsKey(words[i])){ map.put(words[i],1); }else{ value = map.get(words[i])+1; map.put(words[i],value); } } //自定义堆的排序规则:如果不相等,则按照value进行排序;如果相等,则按照字典顺序 Queue<HashMap.Entry<String,Integer>> heap = new PriorityQueue<HashMap.Entry<String,Integer>>(new Comparator<HashMap.Entry<String,Integer>>(){ @Override public int compare(HashMap.Entry<String,Integer> o1, HashMap.Entry<String,Integer> o2) { if(o1.getValue().equals(o2.getValue())){ return o2.getKey().compareTo(o1.getKey()); }else{ return o1.getValue() - o2.getValue(); } } }); //遍历获取单词 for (HashMap.Entry<String, Integer> entry : map.entrySet()) { heap.offer(entry); if (heap.size() > k) { heap.poll(); } } //堆删除元素 List<String> ret = new ArrayList<String>(); while (!heap.isEmpty()) { ret.add(heap.poll().getKey()); } //按照删除顺序是由小到大了,所以需要反转 Collections.reverse(ret); return ret; } }