雜題部分

木木ちゃん發表於2024-11-09

雜題部分

  1. 3131. 找出與陣列相加的整數 I

思路

快排+直接找差值。

void quickSort(int *arr,int low,int high)
{
    if(high<=low) return;
    int i=low;
    int j=high;
    int pivot=arr[low];
    while(1)
    {
        // 1. 自左到右搜尋,直到比pivot大後停止。
        while(arr[i]<=pivot)
        {
            i++;
            if(i==high) break;
        }
        // 2. 自右到左搜尋,直到比pivot小後停止。
        while(arr[j]>=pivot)
        {
            j--;
            if(j==low) break;
        }
        // 3. 兩個指標相遇時或跨越後,停止。
        if(i>=j) break;
        // 4.交換兩個指標的值。
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    // 交換pivot與右指標的值
    arr[low]=arr[j];
    arr[j]=pivot;
    // 分段進行快排
    quickSort(arr,low,j-1);
    quickSort(arr,j+1,high);
}
int addedInteger(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    quickSort(nums1,0,nums1Size-1);
    quickSort(nums2,0,nums2Size-1);
    return nums2[0]-nums1[0];
}
  1. 3132. 找出與陣列相加的整數 II
void quickSort(int *arr,int low,int high)
{
    if(high<=low) return;
    int i=low;
    int j=high;
    int pivot=arr[low];
    while(1)
    {
        // 1. 自左到右搜尋,直到比pivot大後停止。
        while(arr[i]<=pivot)
        {
            i++;
            if(i==high) break;
        }
        // 2. 自右到左搜尋,直到比pivot小後停止。
        while(arr[j]>=pivot)
        {
            j--;
            if(j==low) break;
        }
        // 3. 兩個指標相遇時或跨越後,停止。
        if(i>=j) break;
        // 4.交換兩個指標的值。
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    // 交換pivot與右指標的值
    arr[low]=arr[j];
    arr[j]=pivot;
    // 分段進行快排
    quickSort(arr,low,j-1);
    quickSort(arr,j+1,high);
}

int minimumAddedInteger(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    quickSort(nums1,0,nums1Size-1);
    quickSort(nums2,0,nums2Size-1);
    for(int i=2;i>=0;i--)
    {
        int left=i+1,right=1;
        while(left<nums1Size && right < nums2Size)
        {
            if(nums1[left]-nums2[right]==nums1[i]-nums2[0])
                right++;
            left++;
        }
        if(right==nums2Size)
            return nums2[0]-nums1[i];
    }
    return 0;
}
  1. 3148. 矩陣中的最大得分

思路

方法一:動態規劃

思路與演算法

\(f(i,j)\) 表示以矩陣 \(grid\) 中位置 \((i,j)\) 結束的最大得分。由於每一步只能往右走或者往下走,因此在進行狀態轉移時,我們分別列舉這兩種情況:

對於往右走,我們有:

\[dp(i,j)=\max_{0\leqslant k<j}\{\max\{dp(i,j),0\}+grid(i,j)-grid(i,k)\} \]

這裡的 \(\max\{f(i,k),0\}\) 是由於題目要求「必須至少移動一次」,所以 \(f(i,k)\) 中並不包含「以 \((i,k)\) 同時為起點和終點」的情況,需要增加 0 來表示這一情況,才能讓狀態轉移中包含「以 \((i,k)\) 為起點,\((i,j)\) 為終點」的情況。

就算不考慮往右走的情況,上述狀態轉移方程的時間複雜度也達到了 \(O(mn)×O(n)=O(mn^2)\),會超出時間限制,因此需要進行最佳化。

注意到 \(grid(i,j)\)\(k\) 無關,我們可以將其從 \(max\) 中提出:

\[dp(i,j)=grid(i,j)+\max_{0\leqslant k<j}\{\max\{dp(i,j),0\}-grid(i,k)\} \]

\(prerow(i,j)=\max\limits_{0\leqslant k<j}\{\max\{dp(i,j),0\}-grid(i,k)\}\),那麼可以使用字首和的思想,在計算完 \(f(i,j)\) 後用 \(O(1)\) 的時間得到它的值:

\[\begin{cases} prerow(i,0)=\max\{dp(i,0),0\}−grid(i,0)\\ prerow(i,j)=\max\{prerow(i,j−1),\max\{dp(i,j),0\}−grid(i,j)\} \end{cases} \]

此時狀態轉移方程變為簡單的遞推:

\[dp(i,j)=grid(i,j)+prerow(i,j−1) \]

同理,對於往左走,我們有:

\[dp(i,j)=grid(i,j)+precol(i−1,j) \]

這裡 \(precol(i,j)\) 是與 \(prerow(i,j)\) 類似的列的字首最大值。當所有的 \(dp(i,j)\) 都計算完成後,其中的最大值即為最終的答案。

題解

int maxScore(int** grid, int gridSize, int* gridColSize) {
    // dp 2-dimensional matrix.
    int **dp=(int**)malloc(sizeof(int*)*gridSize);
    int **preRow=(int**)malloc(sizeof(int*)*gridSize);
    int **preCol=(int**)malloc(sizeof(int*)*gridSize);
    for(int i=0;i<gridSize;i++)
    {
        dp[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
        preRow[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
        preCol[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
        for(int j=0;j<gridColSize[i];j++)
        {
            dp[i][j]=-1e8;
            preRow[i][j]=0;
            preCol[i][j]=0;
        }
    }


    int ans=-1e8;
    for(int i=0;i<gridSize;i++)
    {
        for(int j=0;j<gridColSize[i];j++)
        {
            if(i>0)
                dp[i][j]=dp[i][j]>grid[i][j]+preCol[i-1][j]?dp[i][j]:preCol[i-1][j]+grid[i][j];
            
            if(j>0)
                dp[i][j]=dp[i][j]>grid[i][j]+preRow[i][j-1]?dp[i][j]:grid[i][j]+preRow[i][j-1];
            
            ans=ans>dp[i][j]?ans:dp[i][j];
            preRow[i][j]=preCol[i][j]=(dp[i][j]>0?dp[i][j]:0)-grid[i][j];
            if(i>0)
                preCol[i][j]=preCol[i][j]>preCol[i-1][j]?preCol[i][j]:preCol[i-1][j];
            if(j>0)
                preRow[i][j]=preRow[i][j]>preRow[i][j-1]?preRow[i][j]:preRow[i][j-1];
        }
    }
    return ans;
}
  1. 2552.統計四元上升陣列

class Solution {
public:
    long long countQuadruplets(vector<int>& nums) {
        int n=nums.size();
        vector<int> pre(n+1);
        long long ans=0,cur=0;
        for(int j=0;j<n;j++)
        {   
            cur=0;
            for(int k=n-1;k>j;k--)  // 從後往前進行列舉
            {
                if(nums[j]>nums[k])
                    ans += (long long)(pre[nums[k]])*cur;
                else
                    cur++;
            }
            for (int x=nums[j]+1;x<=n;x++)
                pre[x]++;   // 統計從0到j-1的小於x的數
        }
        return ans;
    }
};
  1. 2306. 公司命名

思路(Hash set)

將每一個字元以首字母為key,去掉首字母為字尾儲存在hashset中。這樣我們就有
a: str1,str2,str3...
b: str1,str2,str3...
然後我們觀察是否有重複的字尾。有則去掉。這樣就有了
ans+=(a-repeat)*(b-repeat)
作為最終結果。

Code

class Solution {
public:

    int get_size(unordered_set<string> &a, unordered_set<string> &b)
    {
        // Count for the intersected suffix.
        int ans=0;
        for(const string &s:a)
        {
            if(b.count(s))
                ans++;
        }
        return ans;
    }

    long long distinctNames(vector<string>& ideas) {
        unordered_map<char, unordered_set<string> > names;  // Hash set put all the names with the same first letter together.
        for (string &idea:ideas)
        {
            names[idea[0]].insert(idea.substr(1,idea.size()-1));
        }

        long long ans=0;

        // Check for intersects and count.
        for(auto [key1,val1]:names)
        {
            for(auto [key2,val2]:names)
            {
                if(key1==key2) continue;
                int intersections=get_size(val1,val2);
                ans+=static_cast<long long> (val1.size()-intersections)*(val2.size()-intersections);
            }
        }
        return ans;
    }

};