代码随想录刷题感悟

栈、队列、堆的常用方法

Deque<Integer> stack = new LinkedList<>();
//push(E element): 将元素压入栈顶。
//pop(): 弹出并返回栈顶元素。
//peek(): 返回栈顶元素而不弹出。
//isEmpty(): 检查栈是否为空。
//size(): 返回栈中元素的个数
​
Queue<Integer> queue = new LinkedList();
//offer(E element): 将元素添加到队列尾部。
//poll(): 弹出并返回队列头部元素。
//peek(): 返回队列头部元素而不弹出。
//isEmpty(): 检查队列是否为空。
//size(): 返回队列中元素的个数
​
PriorityQueue<Integer> pq = new PriorityQueue();
//offer(E element): 将元素添加到优先队列中。
//poll(): 弹出并返回优先队列中的最小元素。
//peek(): 返回优先队列中的最小元素而不弹出。
//isEmpty(): 检查优先队列是否为空。
//size(): 返回优先队列中元素的个数

Map 和 List的常用方法:

//Map 常用方法:
Map<String,Integer> map = new HashMap<>(); 
//put(K key, V value): 将指定的键值对添加到 Map 中。
//get(Object key): 根据键获取对应的值。
//containsKey(Object key): 检查 Map 中是否包含指定的键。
//remove(Object key): 删除指定键对应的键值对。
//keySet(): 获取 Map 中所有键的集合。
//values(): 获取 Map 中所有值的集合。
//entrySet(): 获取 Map 中所有键值对的集合。
//isEmpty(): 检查 Map 是否为空。
//size(): 获取 Map 中键值对的数量。
//getOrDefault():如果 Map 中包含指定键的映射关系,就返回该键对应的值;否则,返回设定的默认值。
​
//List 常用方法:
//add(E element): 将元素添加到列表末尾。
//add(int index, E element): 在指定位置插入元素。list的索引也是从0开始的
//get(int index): 获取指定位置的元素。
//set(int index, E element): 修改指定位置的元素。
//remove(int index): 删除指定位置的元素。
//remove(Object o): 删除第一次出现的指定元素。
//contains(Object o): 检查列表是否包含指定元素。
//isEmpty(): 检查列表是否为空。
//size(): 获取列表中元素的数量
​
    // Map 示例
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
int value = map.get("banana"); // value = 2
boolean containsKey = map.containsKey("apple"); // containsKey = true
boolean containsValue = map.containsValue(3); // containsValue = false
map.remove("apple");
Set<String> keys = map.keySet();
Collection<Integer> values = map.values();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
​
// List 示例
List<String> list = new ArrayList<>();
list.add("apple");
list.add(1, "banana");
String element = list.get(1); // element = "banana"
list.set(0, "orange");
list.remove(1);
int index = list.indexOf("apple"); // index = 0
boolean contains = list.contains("banana"); // contains = false
int size = list.size(); // size = 1
list.clear();

数组 

时间复杂度是衡量算法性能的重要指标,表示算法运行所需时间与问题规模之间的关系

空间复杂则则是算法运行所需空间和问题规模之间的关系

1.二分法查找元素,将数组按mid划分

public int binarySearch(int[] arr, int target) {
    int left = 0;
    int right = arr.length - 1;
    while(left <= right) { // 这里取小于等于代表区间右端点能取到,若取不到,则left < right
         int mid = left + (right - left) / 2;
         if(arr[mid] > target) {   
         right = mid - 1;    //相应的这里会是right = mid;
         } else if(arr[mid] < target) {
                left = mid + 1;
         } else {
                return mid;
        }
        }
        return -1;
 

}

2.双指针:快慢指针,左右指针;

快慢指针:利用一个快指针和一个慢指针,在一个for循环里完成两个for循环的工作

pubilc void doublePointer(int[] arr, int target) {  //去重数组中的某个重复元素;
    int low = 0;
    for(int fast = 0; fast < arr.length; fast++) {
        if(arr[fast] == target) {
            arr[low++] = arr[fast];
}
        
}

}

左右指针:利用在一重循环里左指针和右指针,将时间复杂度从O(n^2)降到O(n);

pubilc int[] twoSum(int[] arr, int target) {  //arr是升序排列的
    int left = 0;
    int right = arr.length - 1;
    while(left < right) {
        if(target == arr[left] + arr[right]) {
            return new int[]{left,right};
        }else if(target < arr[left] + arr[right]) {
            right--;
        }esle {
                left++;
              }
    }
    //若没找到则
    return new int[]{-1,-1};   
}

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。

//求解最小连续子序列大于某个值
public int minSubArrayLen(int target, int[] nums) {
    //滑动窗口的左右边界
     int left = 0;
    int right = 0;
    int sum = 0;
    int len = 0;
    int result = nums.length + 1;
    for(;right < nums.length; right++) {
            sum += nums[right];
           while(sum >= target) {
                len = right - left + 1;
                result = len < result ? len : result;
                sum -= nums[left];
                left++;
            }
    }
    return result == nums.length + 1 ? 0: result;
    }

}

递归的三要素:递归终止条件、递归参数和返回类型、单层递归的逻辑

回溯的三要素:回溯函数的返回值和返回类型、回溯函数终止条件、回溯搜索的遍历过程

//回溯模板
void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }
​
    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

动态规划的4步:Dynamic Programming dp

  1. 确定dp数组及下标的含义

  2. 确定递推公式

  3. dp数组初始化

  4. 确定遍历顺序

最长回文子串一类题都是二维动态规划

全排列一类题都是回溯

二叉树的前、中、后序遍历

递归法:
     List<Integer> res = new ArrayList<>()
    public List<Integer> orderTravel(TreeNode root) {
        order(root);
        return res; 
}
    public void order(TreeNode root) {
        if(root == null) return;
        res.add(root);
        order(root.left);
        order(root.right);
        //前中后序遍历递归法的区别在于.add的位置
    }
迭代法:
    前序遍历
    //前序遍历:中->左->右 入栈顺序:中->右->左
 
    public List<Integer> orderTravel(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) {
            return res;
        }
        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode tmp = stack.pop();
            res.add(tmp.val);
            if(tmp.right != null) stack.push(tmp.right);
            if(tmp.left = null) stack.push(tmp.left);
        }
}
中序遍历:左->中->右
  
  public List<Integer> orderTravel(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
​
        while (curr != null || !stack.isEmpty()) {
        // 将当前节点及其左子树全部压入栈中
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
​
            // 弹出栈顶节点,并访问它
            curr = stack.pop();
            result.add(curr.val);
​
            // 转向右子树
            curr = curr.right;
        }
​
        return result;
}
后序遍历:左->右->中

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode curr = root;
    TreeNode prev = null;
    
    while (curr != null || !stack.isEmpty()) {
        // 将当前节点及其左子树全部压入栈中
        while (curr != null) {
            stack.push(curr);
            curr = curr.left;
        }
        
        // 取出栈顶节点
        curr = stack.pop();
        
        // 如果当前节点没有右子节点或者右子节点已经被访问过,则访问当前节点
        if (curr.right == null || curr.right == prev) {
            result.add(curr.val);
            prev = curr;
            curr = null;
        } else { // 否则,将当前节点重新压入栈,并转向右子树
            stack.push(curr);
            curr = curr.right;
        }
    }
    
    return result;
}   
层序遍历

    List<List<Integer> res> = new ArrayList<>();
    public List<Integer> travel(TreeNode root) {
        checkFun(root);
        return res;
    }
    publiv void checkFun(TreeNode root) {
        if (root == null) return;
        Queue<TreeNode> que = new LinkedList<>();
        que.offer(root);
        while (!queue.isEmpty()) {
            List<Integer> resItem = new LinkedList<>();
            int len = que.size();
            while (len > 0) {
               
                TreeNode tmp = que.poll();
                resItem.add(tmp.val);
                if (tmp.left != null) que.offer(tmp.left);
                if (tmp.right != null) que.offer(tmp.right);
                len--;
                
            }
            res.add(resItem);
            
        }
    }

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值