Leetcode第286場周賽

緒論

上周因為有事沒有參加周賽,這周沒有錯過。這次周賽拿到了人生第一個AK,參加大大小小的比賽這么多次,從來沒有AK過,淚目了。
在這里插入圖片描述
感覺這次比賽的思維難度對我來講稍高一些,前三道題就花了一個小時,而以往只需要半個小時。
看了一下排名前面的大牛們,還是十分鐘就AK了,深覺自己還馬達馬達大內。

題目分析

比賽鏈接:https://leetcode-cn.com/contest/weekly-contest-286/

題目難度上第二題和第三題都有一些思維量,不像以前直接模擬。第四題我直接記憶化搜索在最后一分鐘過了,當時學習動態規劃的時候接觸到記憶化搜索對其嗤之以鼻,覺得就是弱者想不出來狀態轉移方程,用這種近似暴力的方式來處理。然后現在發現,弱者竟是我自己,記憶化搜索真香。

A:找出兩數組的不同

簽到題,數據量很小,也沒有仔細想直接兩個哈希集合,去重并判斷每個元素是否在另一個集合出現過,沒有出現過就添加到結果數組中。

class Solution {
public:vector<vector<int>> findDifference(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> s1, s2;for (auto x : nums1) s1.insert(x);for (auto x : nums2) s2.insert(x);vector<vector<int>> ret(2);for (auto x : s1) {if (s2.count(x) == 0) ret[0].push_back(x);}for (auto x : s2) {if (s1.count(x) == 0) ret[1].push_back(x);}return ret;}
};

B:美化數組的最少刪除數

題目的意思就是偶數位置的元素要和下一個位置的元素不相等。因為只向后看, 所以當時想到了一個構造答案的方法:首先統計每個數字連續出現的次數x。對于偶數位置,ans+=x-1,對于奇數位置,ans+=x-2。最后如果要填充奇數位置,則++ans,因為最后一個位置必須要保證數組的長度為偶數。

class Solution {
public:int minDeletion(vector<int>& nums) {vector<pair<int, int>> cnt;int n = nums.size();for (int i = 0; i < n; ) {int j = i + 1;while (j < n && nums[j] == nums[i]) ++j;cnt.emplace_back(nums[i], j - i);i = j;}n = cnt.size();int ans = 0, x;bool is_even = true;for (int i = 0; i < n; ++i) {x = cnt[i].second;if (is_even) {ans += x - 1;is_even = false;} else {if (x == 1) {is_even = true;} else {ans += x - 2;}}}if (!is_even) ++ans;return ans;}
};

這樣做的正確性在于,對于偶數位置,他如果連續出現了多次,最多只能保留1個。對于奇數位置,如果連續出現了多次,最多只能保留2個。這里我們每次都選擇的是盡可能保留以滿足題目中的最短長度。最后我們處理了一下讓整個數組的長度為偶數:如果下一次要填充的是奇數位置的數字,那么說明前面的位置是偶數位置,需要將其刪除。

接下來我們簡單討論一下為什么盡可能保留數字是最優的。假如某個位置我們可以保留某個數字但是我們將其刪光了,后面的數字會移動到前面,同樣需要刪除,并不能讓解更好。詳細的證明需要分類討論之類的,這里我們就不求甚解了。

C:找到指定長度的回文數

是一個對我來講有點思維量的模擬,我們需要能夠構造任意長度,第任意大小的回文串。為了能夠構造第x大的回文串,我們需要使用類似進制轉換的思想。
對于相同長度的回文串,其值和相對大小是由前面一半的數字支配的,后面一半的數字都不用進行考慮。
第一個數字只能是1-9,后面的數字每一位都可以是0-9。對于一個回文串長度為intLength,他的所有可能結果是maxn=9?10intLength?12maxn = 9*10^{\frac{intLength -1}{2}}maxn=9?102intLength?1?。如果x大于maxn,則直接返回-1。
接下來我們來從前往后確定每一位數字的大小。第一位數字確定后,后面的數字有maxn/=9種可能。即第1——maxn個回文串的第一位是1,第maxn+1——2maxn個回文串的第一位是2。為了確定第一位的數字,我們可能想要讓x/maxn來確定。但是整除需要我們特別處理一下。
因為算數運算默認是從0開始的,0——maxn-1 /x都是0。為了尋求這種統一,我們不妨給x減一,從而可以直接套用算術運算。
對于后面的位數也是同樣的道理。總結一下就是為了能夠讓x對固定步長(上面的maxn)進行分組,我們讓x-1,從而將原本1——maxn變成了0——manx-1,變成了在數值意義上的同一組。
后面取余仍然會從0開始,所以我們只用減一一次。

class Solution {using ll = long long;ll n_, maxn_, len_;ll work(ll x) {--x;vector<int> arr;ll n = n_;arr.push_back(x / n + 1);x %= n;ll len = len_;len -= 2;while (len > 0) {n /= 10;arr.push_back(x / n);x %= n;len -= 2;}ll ret = 0;for (auto x : arr) ret = ret * 10 + x;if (len_ & 1) arr.pop_back();int nn = arr.size();for (int i = nn - 1; i >= 0; --i) ret = ret * 10 + arr[i];return ret;}public:vector<long long> kthPalindrome(vector<int>& queries, int intLength) {len_ = intLength;int n = (intLength - 1) >> 1;n_ = 1;for (int i = 0; i < n; ++i) {n_ *= 10;}maxn_ = n_ * 9;vector<ll> ret;for (auto x : queries) {if (x > maxn_) ret.push_back(-1);else {ret.push_back(work(x));}}return ret;}};

仔細研究了一下大牛的解法,發現我這里處理復雜的原因是沒有想到每位填充的也是十進制數字,那么x-1+maxn就是前一半數字。x-1是第一位從0開始的第x個數字,加上maxn就是第一位從1開始的。

D:從棧中取出 K 個硬幣的最大面值和

我們很容易就可以計算出從一個棧中取m個硬幣的面值和,那么問題就是我們可以從n個棧中取硬幣,每個棧可以取0個或多個,最終取k個的最大和。想了一下也沒有什么狀態轉移的,就直接記憶化搜索了。

class Solution {int n_;vector<vector<int>> sum;vector<int> cnt;vector<vector<int>> memo;int dfs(int x, int k) {if (x == n_) {return sum[x][k];} else {if (memo[x][k] != -1) return memo[x][k];int kk = std::min(k, (int)sum[x].size() - 1);for (int i = std::max(0, k - cnt[x]); i <= kk; ++i) {memo[x][k] = max(memo[x][k], sum[x][i] + dfs(x + 1, k - i));}}return memo[x][k] == -1 ? INT_MIN : memo[x][k];}
public:int maxValueOfCoins(vector<vector<int>>& piles, int k) {int n = piles.size();memo.resize(n, vector<int>(k + 1, -1));n_ = n - 1;sum.resize(n);cnt.resize(n);for (int i = 0; i < n; ++i) {auto &arr = piles[i];auto &s = sum[i];s.push_back(0);for (auto x : arr) {s.push_back(s.back() + x);}}int t = 0;for (int i = n - 1; i >= 0; --i) {cnt[i] = t;t += piles[i].size();}return dfs(0, k);}
};

當時最后幾分鐘寫完后一直運行錯誤,我心態有點崩,覺得果然又要到此為止了嗎。但是還是耐下性子去看代碼到底哪里有問題。當時報的是堆上的錯誤,我就覺得是不是哪里數組越界了。認真一看,sum、cnt不可能越界,那是不是備忘錄memo越界了呢?仔細一想,memo的第二個維度是可以取到k的,而我第二個維度的大小只有k,于是將第二個維度的大小改成k+1就過了。
以前寫記憶化搜索都是自己特化一個對pair的哈希然后用unordered_map做,這次因為時間不夠用的二維數組,而之前都沒有寫過用二維數組進行備忘錄,所以就沒注意過這個問題。

雖然時間緊迫,但是我對自己這個記憶化搜索還是挺滿意的,有備忘錄,有必要的剪枝,代碼也很緊湊。
首先初始化了一下memo和sum數組,sum[x][k]表示的是第x個棧取k個硬幣的面值和,memo[x][k]表示的是對于從x到n-1的棧,總共取k個硬幣的最大面值和,最終的答案就是memo[0][k],初始化為-1表示沒有進行更新,如果memo[x][k]不可能存在,則賦值為無窮小。因為我們求的是最大值,所以不會用到這個狀態。

cnt數組是為了剪枝維護的狀態,cnt[x]表示從x+1到n-1總共有多少個硬幣,std::max(0,k-cnt[x])就表示第x個棧至少要取多少枚硬幣才能夠保證從x到n-1能夠取到k個硬幣,std::min(k, (int)sum[x].size()-1)表示第x個棧至多能夠取到多少個硬幣。

總共最多有O(x)*O(k)=2e6個狀態,每個狀態至多求解一次,每個狀態的求解至多是O(k),因此最壞的時間復雜度是2e9。本來心里有些打鼓,但是提交后發現通過了,非常開心。

仔細閱讀了一下大牛的解法,發現是一個01背包問題。感覺自己對背包問題的理解還是不夠深刻,應該專門再整理一下背包問題的思路。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/383517.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383517.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383517.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第287場周賽

緒論 雖然是上周日參加的比賽&#xff0c;但是這周沒有怎么學習&#xff0c;每天就是玩耍。也導致對周賽的總結遲遲沒有進行。想著再拖下去下次周賽都要開始了&#xff0c;在這里補一下。 這場比賽總體比上場簡單一些&#xff0c;但是最后一道題因為忘記初始化類內變量導致調試…

第288場周賽

緒論 雖然沒有AK&#xff0c;但是不知道為什么排名比以前AK了都靠前。可能是因為最后一道題有些難度&#xff0c;縮小了我和大佬之間的差距。最后一個小時寫最后一道題&#xff0c;累死累活想了一個貪心遍歷的算法&#xff0c;當時是一直RE&#xff0c;后來下來調了調又WA了。 …

Clion遠程部署和運行

緒論 作為Clion的忠實粉絲&#xff0c;現在的我的幾乎所有的coding都是通過Clion完成。因為需要在服務器上進行開發&#xff0c;又離不開Clion&#xff0c;就了解了如何通過Clion遠程部署和開發。 主要是借鑒了博客&#xff1a;使用Clion優雅的完全遠程自動同步和遠程調試c。如…

C++ 單例模式 call_once : terminate called after throwing an instance of ‘std::system_error‘

在學習了C中可以使用call_once進行初始化資源后&#xff0c;我就想著寫一個單例模板供以后使用。 template<typename T> class SingleTon {using Ptr std::shared_ptr<T>;static Ptr p;static std::once_flag flag;template<typename ...Args>static void …

C++讀寫鎖造成死鎖

C14支持std::shared_timed_mutex C17支持std::shared_mutex 前者相比后者支持的操作更多&#xff0c;但是后者相對性能更好。 使用std::lock_guard<std::shared_mutex>和std::unique_lock<std::shared_mutex>互斥訪問使用std::shared_lock<std::shared_mutex…

每日一題:449. 序列化和反序列化二叉搜索樹

題目分析 題目鏈接&#xff1a;449. 序列化和反序列化二叉搜索樹 覺得序列化很簡單&#xff0c;前序遍歷、后序遍歷、中序遍歷、層序遍歷等等。其中得到前序遍歷和后序遍歷是可以通過遞歸解法反序列化的&#xff0c;覺得這樣子做有點復雜。就想著可不可以一次遍歷。一次遍歷的…

C++高效集合數據結構設計

緒論 在復雜算法實現過程中我們經常會需要一個高效的集合數據結構&#xff0c;支持常數級別的增、刪、查&#xff0c;以及隨機返回、遍歷&#xff0c;最好還能夠支持交集、并集、子集操作 哈希集合實現 大家可能很快想到unordered_set&#xff0c;unordered_set由于底層是哈…

C++ 工具函數庫

在寫一些大型項目的過程中經常需要一些工具函數&#xff0c;例如獲取隨機數、計時器、打印函數、重要常量&#xff08;如最大值&#xff09;、信號與槽等&#xff0c;由于每一個工程都自己手動實現一個實在是太傻&#xff0c;我將其總結放入一個文件中。 utils.h // Copyright…

muduo網絡庫使用入門

muduo網絡庫介紹 muduo網絡庫是陳碩大神開發的基于主從Reactor模式的&#xff0c;事件驅動的高性能網絡庫。 網絡編程中有很多是事務性的工作&#xff0c;使用muduo網絡庫&#xff0c;用戶只需要填上關鍵的業務邏輯代碼&#xff0c;并將回調注冊到框架中&#xff0c;就可以實…

C++ map/unordered_map元素類型std::pair<const key_type, mapped_type>陷阱

在開發的過程中需要遍歷一個unordered_map然后把他的迭代器傳給另一個對象&#xff1a; class A; class B { public:void deal(const std::pair<int, A>& item); }; std::unordered_map<int, A> mp; B b; for (auto &pr : mp) {b.deal(pr); }在我的項目中…

Ubuntu install ‘Bash to dock‘

緒論 在Ubuntu環境搭建這篇博客中記錄了使用Dash To Dock來配置Ubuntu的菜單項&#xff0c;使得實現macOS一樣的效果。為了配置新電腦的環境&#xff0c;我還是想安裝這個軟件。但是如今在Ubuntu Software中已經找不到這個軟件了&#xff0c;我在網上借鑒了一些博客的經驗才得…

Leetcode第309場周賽

Date: September 4, 2022 Difficulty: medium Rate by others: ???? Time consuming: 1h30min 題目鏈接 競賽 - 力扣 (LeetCode) 題目解析 2399. 檢查相同字母間的距離 class Solution {public:bool checkDistances(string s, vector<int>& distance) {vec…

C++ 模板函數、模板類:如果沒有被使用就不會被實例化

C中如果一個模板函數沒有使用過&#xff0c;那么其局部靜態變量都不會被實例化&#xff1a; class A { public:A() {edward::print("A ctor");} };template<typename T> void test() {static A a; }int main() {test<int>(); //如果注釋掉則不會有輸出r…

C++ 條件變量的使用

緒論 并發編程紛繁復雜&#xff0c;其中用于線程同步的主要工具——條件變量&#xff0c;雖然精悍&#xff0c;但是要想正確靈活的運用卻并不容易。 對于條件變量的理解有三個難點&#xff1a; 為什么wait函數需要將解鎖和阻塞、喚醒和上鎖這兩對操作編程原子的&#xff1f;為…

C++Primer學習筆記:第1章 開始

本博客為閱讀《C Primer》&#xff08;第5版&#xff09;的讀書筆記 ps:剛開始的時候我將所有的筆記都放在一篇博客中&#xff0c;等看到第六章的時候發現實在是太多了&#xff0c;導致我自己都不想看&#xff0c;為了日后回顧&#xff08;不那么有心理壓力&#xff09;&#…

【ubuntu】ubuntu14.04上安裝搜狗輸入法

** 在ubuntu14.04.4 desktop 64amd版本上安裝sogou輸入法 ** 0.換安裝源為中國源&#xff08;可選&#xff0c;下載會快些&#xff09; 1.搭fcitx環境 2.安裝sogou for linux 詳細步驟&#xff1a; 因為sogou中文輸入法基于fcitx(Free Chinese Input Toy for X),需要先搭環境…

【ubuntu】ubuntu下用make編譯程序報錯找不到openssl/conf.h

ubuntu下用make編譯程序報錯找不到openssl/conf.h 安裝libssl-dev:i386&#xff0c;sudo apt-get install libssl-dev:i386 看好版本&#xff0c;如果不加i386默認下載的是32位&#xff0c;用ln命令連接過去也還是用不了的!libssl.dev安裝好后&#xff0c;用find / -name libs…

【ubuntu】ubuntu如何改變系統用戶名

ubuntu如何改變系統用戶名 方法1&#xff1a;修改現有用戶名 方法2&#xff1a;創建新用戶&#xff0c;刪掉舊用戶 方法1&#xff1a; * *—&#xff01;&#xff01;&#xff01;有博客說要先改密碼&#xff0c;再改用戶名&#xff0c;否則會出現無法登陸狀況&#xff01;&…

什么是signal(SIGCHLD, SIG_IGN)函數

什么是signal(SIGCHLD, SIG_IGN)函數 在進行網絡編程時候遇到這個函數的使用&#xff0c;自己學習結果如下&#xff0c;有不對請幫忙指正:) signal(SIGCHLD, SIG_IGN)打開manpage康一康~ sighandler_t signal ( int signum, sighandler_t handler );參數1 int signum: 就是…

ssh連接不上linux虛擬機

ssh連接不上linux虛擬機 1.開啟ssh服務 linux虛擬機下命令行輸入&#xff1a; start service ssh如果顯示沒有ssh&#xff0c;就下面兩個試一試哪一個ok&#xff0c;安裝一下ssh&#xff1a; sudo apt-get install openssh-server sudo apt-get install sshd2.還有人說可能是…