算法刷题记录(LeetCode 421-450)

文章介绍了多个编程题目,包括最长重复字符替换、N-ary树的层次遍历、最小基因突变、字符串分段计数、寻找右区间、路径和遍历、查找字串的排列以及删除BST中的节点。涉及的主要算法有双指针、莫队思想、前缀和、深度优先搜索等,同时强调了哈希表和二分查找在解决这些问题中的作用。
摘要由CSDN通过智能技术生成

*424. Longest Repeating Character Replacement

    int characterReplacement(string s, int k) {
        if (s.size()==0){
            return 0;
        }
        int alphabet[26];
        fill(alphabet,alphabet+26,0);
        int left=0;
        int right=0;
        int res=0;
        while (right<s.size()){
            alphabet[s[right]-'A']++;
            while (right-left+1-*max_element(alphabet,alphabet+26)>k){
                alphabet[s[left]-'A']--;
                left++;
            }
            res=max(res,right-left+1);
            right++;
        }
        return res;
    }

429. N-ary Tree Level Order Traversal

    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> ans=new ArrayList<>();
        if (root==null){
            return ans;
        }
        Queue<Node> queue=new LinkedList<>();
        Queue<Node> curr=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            List<Integer> currLayerNodes=new ArrayList<>();
            while (!queue.isEmpty()){
                Node node=queue.poll();
                if (node.children!=null){
                    for (Node child:node.children){
                        curr.offer(child);
                    }
                }
                currLayerNodes.add(node.val);
            }
            queue.addAll(curr);
            curr.clear();
            ans.add(currLayerNodes);
        }
        return ans;
    }

*433. Minimum Genetic Mutation

class Solution {
    public static final char[] charSet = {'A', 'G', 'C', 'T'};
    public HashMap<String, Integer> map = new HashMap<>();

    public int minMutation(String startGene, String endGene, String[] bank) {
        HashSet<String> alphabet = new HashSet<>(bank.length);
        Collections.addAll(alphabet, bank);
        map.put(startGene, 0);
        Deque<String> deque = new ArrayDeque<>();
        deque.addLast(startGene);
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size > 0) {
                String s = deque.pollFirst();
                int currStep = map.get(s);
                char[] charArr = s.toCharArray();
                for (int i = 0; i < 8; i++) {
                    char[] sourceCopy = charArr.clone();
                    for (char ch : charSet) {
                        if (sourceCopy[i] == ch) {
                            continue;
                        }
                        sourceCopy[i] = ch;
                        String variant = new String(sourceCopy);
                        if (!alphabet.contains(variant)) continue;
                        if (endGene.equals(variant)) {
                            return currStep + 1;
                        }
                        if (map.containsKey(variant)) continue;
                        map.put(variant, currStep + 1);
                        deque.addLast(variant);
                    }
                }
                size--;
            }
        }
        return -1;
    }
}

434. Number of Segments in a String

import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
    String regex="\\S+";
    Pattern pattern=Pattern.compile(regex);
    public int countSegments(String s) {
        if (s.isEmpty()){
            return 0;
        }
        Matcher matcher=pattern.matcher(s);
        String[] res=s.split(" ");
        int cnt=0;
        while (matcher.find()){
            cnt++;
        }
        return cnt;
    }
}

*436. Find Right Interval

排序+二分 注意 mid的对left以及right取值影响

class Solution {
    public int[] findRightInterval(int[][] its) {
        int n = its.length;
        int[][] clone = new int[n][2];
        for (int i = 0; i < n; i++) clone[i] = new int[]{its[i][0], i};
        Arrays.sort(clone, (a,b)->a[0]-b[0]);
        int[] ans = new int[n];
        for (int i = 0; i < n; i++) {
            int l = 0, r = n - 1;
            while (l < r) {
                int mid = l + r >> 1;
                if (clone[mid][0] >= its[i][1]) r = mid;
                else l = mid + 1;
            }
            ans[i] = clone[r][0] >= its[i][1] ? clone[r][1] : -1;
        }
        return ans;
    }
}

双指针(莫队思想)

更进一步,在解法一中我们并没有对求解询问的顺序进行调整,这导致了我们不得不每次都在整个左端点序列中进行二分。

朴素处理询问的方式,需要每次对整个序列进行扫描,复杂度为 O ( n 2 ) O(n^2) O(n2)实际上,如果我们按照「右端点从小到大」的顺序处理询问,其每个询问对应的「最右区间的左端点」也具有单调特性。

因此,我们可以运用莫队思想:通过调整询问的处理顺序,来减少扫描目标位置的指针移动次数。将其从「必然进行 O ( n 2 ) O(n^2) O(n2)次移动」优化为「最多不超过n次移动」,从而将 构造答案 的复杂度从 O ( n 2 ) O(n^2) O(n2)优化为 O ( n ) O(n) O(n)

*437. Path Sum III

树的遍历 + DFS

class Solution {
    public int res=0;
    public static long target;
    public int pathSum(TreeNode root, int targetSum) {
        target=targetSum;
        dfsStartRoute(root);
        return res;
    }
    public void dfsStartRoute(TreeNode root){
        if (root==null){
            return;
        }
        dfsSubRoute(root, 0);
        dfsStartRoute(root.left);
        dfsStartRoute(root.right);
    }
    public void dfsSubRoute(TreeNode root,long currSum){
        if (currSum+root.val==target){
            res++;
        }
        if (root.left!=null){
            dfsSubRoute(root.left,currSum+root.val);
        }
        if (root.right!=null){
            dfsSubRoute(root.right,currSum+root.val);
        }
    }
}

*树的遍历 + 前缀和

在「解法一」中,我们统计的是以每个节点为根的(往下的)所有路径,也就是说统计的是以每个节点为「路径开头」的所有合法路径。

本题的一个优化切入点为「路径只能往下」,因此如果我们转换一下,统计以每个节点为「路径结尾」的合法数量的话,配合原本就是「从上往下」进行的数的遍历(最完整的路径必然是从原始根节点到当前节点的唯一路径),相当于只需要在完整路径中找到有多少个节点到当前节点的路径总和为
targetSum。于是这个树上问题彻底转换一维问题:求解从原始起点(根节点)到当前节点 b 的路径中,有多少节点 a 满足: s u m [ a . . . b ] = t a r g e t S u m sum[a...b]=targetSum sum[a...b]=targetSum,由于从原始起点(根节点)到当前节点的路径唯一,因此这其实是一个「一维前缀和」问题。

具体的,我们可以在进行树的遍历时,记录下从原始根节点 root 到当前节点 cur 路径中,从 root 到任意中间节点 x 的路径总和,配合哈希表,快速找到满足以 cur 为「路径结尾」的、使得路径总和为 targetSum的目标「路径起点」有多少个。

一些细节:由于我们只能统计往下的路径,但是树的遍历会同时搜索两个方向的子树。因此我们应当在搜索完以某个节点为根的左右子树之后,应当回溯地将路径总和从哈希表中删除,防止统计到跨越两个方向的路径。

438. Find All Anagrams in a String

    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res=new ArrayList<>();
        int windowLength=p.length();
        if (s.length()<windowLength){
            return res;
        }
        int[] alphabet=new int[256];
        for (char ch:p.toCharArray()){
            alphabet[ch]++;
        }
        int waitToMinus=p.length();
        char[] sArr=s.toCharArray();
        int right=windowLength-1;
        for (int i=0;i<=right;i++){
            if (alphabet[sArr[i]]>0){
                waitToMinus--;
            }
            alphabet[sArr[i]]--;
        }
        if (waitToMinus==0){
            res.add(0);
        }
        int left=0;
        right++;
        while (right<s.length()){
            alphabet[sArr[left]]++;
            if (alphabet[sArr[left]]>0){
                waitToMinus++;
            }
            if (alphabet[sArr[right]]>0){
                waitToMinus--;
            }
            alphabet[sArr[right]]--;
            if (waitToMinus==0){
                res.add(left+1);
            }
            right++;
            left++;
        }
        return res;
    }

440. K-th Smallest in Lexicographical Order Source

    public int findKthNumber(int n, int k) {
        if(n<k||k<1){
            return 0;
        }
        if(n<10){
            return k;
        }
        long curr=1;
        k--;
        while(k>0){
            long steps=0,first=curr, last=curr+1;
            while (first<=n){
                //限制该位得数字为0-9
                steps+=Math.min(n+1,last)-first;
                first*=10;
                last*=10;
            }
            // 当前steps超位,需要进位
            if(steps<=k){
                curr++;
                k-=steps;
            }
            else {
                curr*=10;
                k--;
            }
        }
        return (int)curr;
    }

441. Arranging Coins

class Solution {
public:
    int arrangeCoins(int _n) {
        long layers = 0;
        long n = _n;
        while ((long)((layers + 1) * layers) / 2 < n) {
            layers += 3;
        }
        while ((long)((layers + 1) * layers)/2 > n){
            layers--;
        }
        if ((long)((layers + 1) * layers)/2 == n){
            return layers;
        }
        return layers;
    }
};

448. Find All Numbers Disappeared in an Array

    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i) {
            int curr_val= abs(nums[i])%nums.size();
            int target_val=abs(nums[curr_val]);
            nums[curr_val]=-target_val;
        }
        if (nums[0]>0){
            res.push_back(nums.size());
        }
        for (int i = 1; i < nums.size(); ++i) {
            if (nums[i]>0){
                res.push_back(i);
            }
        }
        return res;
    }

*450. Delete Node in a BST


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值