算法刷题记录(LeetCode 331-360)

332. Reconstruct Itinerary

    vector<string> res;
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        res.push_back("JFK");
        sort(tickets.begin(),tickets.end());
        map<string,vector<string>> adj;
        for (auto val:tickets) {
            adj[val[0]].push_back(val[1]);
        }
        dfs("JFK",tickets.size(),adj);
        return res;
    }
    bool dfs(const string& src,int target_length,map<string,vector<string>> adj){
        if (res.size()==target_length+1){
            return true;
        }
        if (adj.find(src)==adj.end()){
            return false;
        }
        vector<string> copy(adj[src]);
        for(int i=0;i<copy.size();i++){
            string val=copy.at(i);
            res.push_back(copy.at(i));
            adj[src].erase(adj[src].begin()+i);
            if (dfs(val,target_length,adj)){
                return true;
            }
            res.pop_back();
            adj[src].insert(adj[src].begin()+i,val);
        }
        return false;
    }

*334. Increasing Triplet Subsequence

    bool increasingTriplet(vector<int>& nums) {
        int n = nums.size(), ans = 1;
        vector<int> f(n + 1, INT_MAX);
        for(int i = 0; i < n; i++){
            int t = nums[i];
            int L = 1, R = i + 1;
            while(L < R){
                int mid = (L + R) >> 1;
                if(f[mid] >= t) R = mid;
                else L = mid + 1;
            }
            f[R] = t;
            ans = max(ans, R);
        }
        return ans >= 3;
    }

简单来说,就是在遍历每个数 nums[i] 的同时,维护一个具有单调性的 f[] 数组,其中 f[len]=x 代表长度为 len 的最长上升子序列最小结尾元素为 x,可以证明 f 数组具有单调性(看 前置🧀),因此每次可以通过二分找到小于 nums[i] 的最大下标,来作为 nums[i] 的前一个数。

338. Counting Bits

    vector<int> countBits(int n) {
        vector<int> res(n+1,0);
        res[0]=0;
        if (n==0){
            return res;
        }
        res[1]=1;
        int i=2;
        int length=2;
        while(i+length<=n){
            for(int j=0;j<length;j++){
                res[i+j]=res[i+j-length]+1;
            }
            i+=length;
            length*=2;
        }
        for (int j = i; j <=n ; ++j) {
            res[j]=res[j-length]+1;
        }
        return res;
    }

*342. Power of Four

    bool isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
    }

343. Integer Break

递归解法(19以上会超时)

class Solution {
    public static int totalInteger;
    public int integerBreak(int n) {
        totalInteger=n;
        return dfs(n);

    }
    public int dfs(int num){
        int res;
        if(totalInteger==num){
            res=0;
        }
        else{
            res=num;
        }
        if(num==1){
            return 1;
        }
        for(int i=1;i<num;i++){
            res = Math.max(dfs(i)*dfs(num-i),res);
        }
        return res;
    }
}

动态规划解法

    public int integerBreak(int n) {
        if(n==1){
            return 1;
        }
        int[] dp=new int[n+1];
        dp[1]=1;
        for(int i=2;i<=n;i++){
            if(i==n){
                dp[i]=0;
            }
            else{
                dp[i]=i;
            }
            for(int j=1;j<i;j++){
                dp[i]=Math.max(dp[j]*dp[i-j],dp[i]);
            }
        } 
        return dp[n];
    }

数学方法

原网址:https://math.stackexchange.com/questions/1860096/maximize-the-product-of-the-partitions-of-an-integer
对于:
n = x 1 + x 2 + . . . + x k n=x_1+x_2+...+x_k n=x1+x2+...+xk

S ( n ) = ∏ i = 1 k x i S(n)=\prod_{i=1}^{k} x_i S(n)=i=1kxi
对两边取 ln ⁡ ( ) \ln() ln()得:
ln ⁡ S ( n ) = ∑ i = 1 k ln ⁡ x i \ln S(n)=\sum_{i=1}^{k} \ln x_i lnS(n)=i=1klnxi
我们知道,对于给定数 m m m x i + x 2 = m x_i+x_2=m xi+x2=m求最大的 x 1 ∗ x 2 x_1*x_2 x1x2当且仅当 x 1 = x 2 = m / 2 x_1=x_2=m/2 x1=x2=m/2时取得。
因此我们可以令:
x = x 1 = x 2 = . . . x k x=x_1=x_2=...x_k x=x1=x2=...xk:
那么原式转化为:
ln ⁡ S ( n ) = k ∗ ln ⁡ x k \ln S(n)=k* \ln{ \frac{x}{k}} lnS(n)=klnkx
k k k求导得:

ln ⁡ x k = 1 \ln{ \frac{x}{k}} = 1 lnkx=1
因此当 x / k = 1 x/k=1 x/k=1 k ≈ 3 k \approx 3 k3时取得最大值。

    public int integerBreak(int n) {
        if(n==2){
            return 1;
        }
        if(n==3){
            return 2;
        }
        int times=n/3;
        int residual=n%3;
        if(residual<2){
            return(int)Math.pow(3,times-1)*(residual+3);
        }
        else{
            return(int)Math.pow(3,times)*(residual);
        }
    }

344. Reverse String

Stack

    void reverseString(vector<char>& s) {
        stack<char> stack1;
        for(char  ch: s){
            stack1.push(ch);
        }
        for (char & i : s) {
            i=stack1.top();
            stack1.pop();
        }
    }

Swap

    void reverseString(vector<char>& s) {
        int start=0;
        int end=s.size()-1;
        while(start<end){
            char tmp=s[start];
            s[start]=s[end];
            s[end]=tmp;
            start++;
            end--;
        }
    }

345. Reverse Vowels of a String

    string reverseVowels(string s) {
        int left=0;
        int right=s.size()-1;
        vector<bool> vowel(256, false);
        vowel['a']=true;
        vowel['i']=true;
        vowel['u']=true;
        vowel['e']=true;
        vowel['o']=true;
        vowel['A']=true;
        vowel['I']=true;
        vowel['U']=true;
        vowel['E']=true;
        vowel['O']=true;
        while(left<right){
            while(left<right&&!vowel[s[left]]){
                left++;
            }
            while (left<right&&!vowel[s[right]]){
                right--;
            }
            char tmp=s[left];
            s[left]=s[right];
            s[right]=tmp;
            left++;
            right--;
        }
        return s;
    }

347. Top K Frequent Elements

反向映射次数HashMap

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        ArrayList<Integer> res = new ArrayList<>();
        HashMap<Integer, Integer> occurrence = new HashMap<>();
        HashMap<Integer, ArrayList<Integer>> occurrenceReversed = new HashMap<>(nums.length);
        for (var val : nums) {
            occurrence.put(val, occurrence.getOrDefault(val, 0) + 1);
        }
        for (var entry : occurrence.entrySet()) {
            if (!occurrenceReversed.containsKey(entry.getValue())) {
                occurrenceReversed.put(entry.getValue(), new ArrayList<>());
                occurrenceReversed.get(entry.getValue()).add(entry.getKey());
            } else {
                occurrenceReversed.get(entry.getValue()).add(entry.getKey());
            }
        }
        int curr = nums.length;
        while (k > 0) {
            if (occurrenceReversed.containsKey(curr)) {
                for (var val : occurrenceReversed.get(curr)) {
                    res.add(val);
                    k--;
                    if (k == 0) {
                        return res.stream().mapToInt(i -> i).toArray();
                    }
                }
            }
            curr--;
            
        }
        return res.stream().mapToInt(i -> i).toArray();
    }
}

349. Intersection of Two Arrays(Solved)

使用流

    public int[] intersection(int[] nums1, int[] nums2) {
        HashSet<Integer> distinct1=new HashSet<>();
        for (var val:nums1){
            distinct1.add(val);
        }
        ArrayList<Integer> res=new ArrayList<>();
        for (var val:nums2){
            if (distinct1.contains(val)){
                res.add(val);
                distinct1.remove(val);
            }
        }
        return res.stream().mapToInt(i->i).toArray();
    }

普遍遍历,速度更快(-50%)

    public int[] intersection(int[] nums1, int[] nums2) {
        HashSet<Integer> distinct1=new HashSet<>();
        for (var val:nums1){
            distinct1.add(val);
        }
        ArrayList<Integer> res=new ArrayList<>();
        for (var val:nums2){
            if (distinct1.contains(val)){
                res.add(val);
                distinct1.remove(val);
            }
        }
        int[] intRes=new int[res.size()];
        for (int i=0;i< res.size();i++){
            intRes[i]=res.get(i);
        }
        return intRes;
        // return res.stream().mapToInt(i->i).toArray();
    }

350. Intersection of Two Arrays II

    public int[] intersect(int[] nums1, int[] nums2) {
        int[] dict=new int[1001];
        for (int val:nums1){
            dict[val]++;
        }
        ArrayList<Integer> res=new ArrayList<>(1000);
        for (int val:nums2){
            if (dict[val]>0){
                res.add(val);
                dict[val]--;
            }
        }
        int[] resArr=new int[res.size()];
        for (int i=0;i<res.size();i++){
            resArr[i]=res.get(i);
        }
        return resArr;
    }

* 354. Russian Doll Envelopes

Solution

这道题的解法是比较巧妙的:

先对宽度 w 进行升序排序,如果遇到 w 相同的情况,则按照高度 h 降序排序。之后把所有的 h 作为一个数组,在这个数组上计算 LIS 的长度就是答案。

画个图理解一下,先对这些数对进行排序:

然后在 h 上寻找最长递增子序列:

这个子序列就是最优的嵌套方案。

这个解法的关键在于,对于宽度 w 相同的数对,要对其高度 h 进行降序排序。因为两个宽度相同的信封不能相互包含的,逆序排序保证在w 相同的数对中最多只选取一个

Half Correct
    public int maxEnvelopes(int[][] envelopes) {
        Arrays.sort(envelopes,(a,b)->{
            if (a[0]!=b[0]){
                return a[0]-b[0];
            }
            return b[1]-a[1];
        });
        int[] height=new int[envelopes.length];
        for (int i=0;i<envelopes.length;i++){
            height[i]=envelopes[i][1];
        }
        return lengthOfLis(height);
    }
    public int lengthOfLis(int[] arr){
        int[] longest=new int[arr.length];
        Arrays.fill(longest,1);
        int longestVal=1;
        for(int i=1;i<arr.length;i++){
            for (int j=0;j<i;j++){
                if (arr[i]>arr[j]){
                    longest[i]=Math.max(longest[i],1+longest[j]);
                }
            }
            longestVal=Math.max(longestVal,longest[i]);
        }
        return longestVal;
    }
Revised LIS
    public int maxEnvelopes(int[][] envelopes) {
        Arrays.sort(envelopes,(a,b)->{
            if (a[0]!=b[0]){
                return a[0]-b[0];
            }
            return b[1]-a[1];
        });
        int[] height=new int[envelopes.length];
        for (int i=0;i<envelopes.length;i++){
            height[i]=envelopes[i][1];
        }
        return lengthOfLIS(height);
    }
    public int lengthOfLIS(int[] nums) {
        int piles = 0, n = nums.length;
        int[] top = new int[n];
        for (int i = 0; i < n; i++) {
            // 要处理的扑克牌
            int poker = nums[i];
            int left = 0, right = piles;
            // 二分查找插入位置
            while (left < right) {
                int mid = (left + right) / 2;
                if (top[mid] >= poker)
                    right = mid;
                else
                    left = mid + 1;
            }
            if (left == piles) piles++;
            // 把这张牌放到牌堆顶
            top[left] = poker;
        }
        // 牌堆数就是 LIS 长度
        return piles;
    }

357. Count Numbers with Unique Digits

    public int countNumbersWithUniqueDigits(int n) {
        if (n == 0) {
            return 1;
        }
        int ways = 10;
        if (n == 1) {
            return ways;
        }
        for (int i = 2; i <= n; i++) {
//            ways+=selectWays(9,1)* selectWays(9,n-1)*permutations(i-1);
            ways += 9 * permutations2(9, i - 1);
        }
        
        return ways;
    }

    public int selectWays(int n, int c) {
        if (c == 0) {
            return 0;
        }
        int base = n;
        for (int i = n - 1; i > n - c; i--) {
            base *= i;
        }
        int factor = c;
        for (int i = c - 1; i > 1; i--) {
            factor *= i;
        }
        return base / factor;
    }

    public int permutations(int n) {
        int res = n;
        for (int i = n - 1; i > 1; i--) {
            res *= i;
        }
        return res;
    }

    public int permutations2(int n, int c) {
        int res = n;
        for (int i = n - 1; i > n - c; i--) {
            res *= i;
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值