周赛传送门
https://leetcode-cn.com/contest/weekly-contest-165/
5275. 找出井字棋的获胜者
题目
A 和 B 在一个 3 x 3 的网格上玩井字棋。
井字棋游戏的规则如下:
- 玩家轮流将棋子放在空方格 (“ “) 上。
- 第一个玩家 A 总是用 “X” 作为棋子,而第二个玩家 B 总是用 “O” 作为棋子。
- “X” 和 “O” 只能放在空方格中,而不能放在已经被占用的方格上。
- 只要有 3 个相同的(非空)棋子排成一条直线(行、列、对角线)时,游戏结束。
- 如果所有方块都放满棋子(不为空),游戏也会结束。
- 游戏结束后,棋子无法再进行任何移动。
给你一个数组 moves
,其中每个元素是大小为 2
的另一个数组(元素分别对应网格的行和列),它按照 A 和 B 的行动顺序(先 A 后 B)记录了两人各自的棋子位置。
如果游戏存在获胜者(A 或 B),就返回该游戏的获胜者;如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。
你可以假设 moves
都 有效(遵循井字棋规则),网格最初是空的,A 将先行动。
示例 1:
1 2 3 4 5 6
| 输入:moves = [[0,0],[2,0],[1,1],[2,1],[2,2]] 输出:"A" 解释:"A" 获胜,他总是先走。 "X " "X " "X " "X " "X " " " -> " " -> " X " -> " X " -> " X " " " "O " "O " "OO " "OOX"
|
示例 2:
1 2 3 4 5 6
| 输入:moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]] 输出:"B" 解释:"B" 获胜。 "X " "X " "XX " "XXO" "XXO" "XXO" " " -> " O " -> " O " -> " O " -> "XO " -> "XO " " " " " " " " " " " "O "
|
示例 3:
1 2 3 4 5 6
| 输入:moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]] 输出:"Draw" 输出:由于没有办法再行动,游戏以平局结束。 "XXO" "OOX" "XOX"
|
示例 4:
1 2 3 4 5 6
| 输入:moves = [[0,0],[1,1]] 输出:"Pending" 解释:游戏还没有结束。 "X " " O " " "
|
提示:
- 1 <= moves.length <= 9
- moves[i].length == 2
- 0 <= moves[i][j] <= 2
moves
里没有重复的元素。
moves
遵循井字棋的规则。
题解
基本上就是枚举解决,但是使用一些小操作可以稍微简化一下,就比如说一开始就手动将九宫格里填满不一样的数字(不是A和B就行),然后将九宫格开成char的直接存A和B,这样直接返回数组值就完了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Solution { public: string tictactoe(vector<vector<int>>& moves) { char g[9][9]; int n=0; char c='0'; for(int i=0;i<3;i++) for(int j=0;j<3;j++) g[i][j]=c,c++; for(auto x:moves){ if(n&1) g[x[0]][x[1]]='B'; else g[x[0]][x[1]]='A'; n++; } string ans; for(int i=0;i<3;i++) if(g[i][0]==g[i][1]&&g[i][1]==g[i][2]) return ans+=g[i][0]; for(int i=0;i<3;i++) if(g[0][i]==g[1][i]&&g[1][i]==g[2][i]) return ans+=g[0][i]; if(g[0][0]==g[1][1]&&g[1][1]==g[2][2]) return ans+=g[0][0]; if(g[0][2]==g[1][1]&&g[1][1]==g[2][0]) return ans+=g[0][2]; if(n==9) return "Draw"; else return "Pending"; } };
|
5276. 不浪费原料的汉堡制作方案
题目
圣诞活动预热开始啦,汉堡店推出了全新的汉堡套餐。为了避免浪费原料,请你帮他们制定合适的制作计划。
给你两个整数 tomatoSlices
和 cheeseSlices
,分别表示番茄片和奶酪片的数目。不同汉堡的原料搭配如下:
- 巨无霸汉堡:4 片番茄和 1 片奶酪
- 小皇堡:2 片番茄和 1 片奶酪
请你以 [total_jumbo, total_small]
([巨无霸汉堡总数,小皇堡总数])的格式返回恰当的制作方案,使得剩下的番茄片 tomatoSlices
和奶酪片 cheeseSlices
的数量都是 0
。
如果无法使剩下的番茄片 tomatoSlices
和奶酪片 cheeseSlices
的数量为 0
,就请返回 []
。
示例 1:
1 2 3
| 输入:tomatoSlices = 16, cheeseSlices = 7 输出:[1,6] 解释:制作 1 个巨无霸汉堡和 6 个小皇堡需要 4*1 + 2*6 = 16 片番茄和 1 + 6 = 7 片奶酪。不会剩下原料。
|
示例 2:
1 2 3
| 输入:tomatoSlices = 17, cheeseSlices = 4 输出:[] 解释:只制作小皇堡和巨无霸汉堡无法用光全部原料。
|
示例 3:
1 2 3
| 输入:tomatoSlices = 4, cheeseSlices = 17 输出:[] 解释:制作 1 个巨无霸汉堡会剩下 16 片奶酪,制作 2 个小皇堡会剩下 15 片奶酪。
|
示例 4:
1 2
| 输入:tomatoSlices = 0, cheeseSlices = 0 输出:[0,0]
|
示例 5:
1 2
| 输入:tomatoSlices = 2, cheeseSlices = 1 输出:[0,1]
|
提示:
- 0 <= tomatoSlices <= 10^7
- 0 <= cheeseSlices <= 10^7
题解
鸡兔同笼问题啊,就是解一个二元一次方程组
限制就是x和y必须为整数且大于等于0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public: vector<int> numOfBurgers(int a, int b) { int t=a-b; if((a-2*b)%2) return vector<int>(); int x=(a-2*b)/2; if(x<0) return vector<int>(); if((a-4*x)%2) return vector<int>(); int y=(a-4*x)/2; if(y<0) return vector<int>(); if(x+y!=b) return vector<int>(); return vector<int>({x,y}); } };
|
5277. 统计全为 1 的正方形子矩阵
题目
给你一个 m * n
的矩阵,矩阵中的元素不是 0
就是 1
,请你统计并返回其中完全由 1
组成的 正方形 子矩阵的个数。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12
| 输入:matrix = [ [0,1,1,1], [1,1,1,1], [0,1,1,1] ] 输出:15 解释: 边长为 1 的正方形有 10 个。 边长为 2 的正方形有 4 个。 边长为 3 的正方形有 1 个。 正方形的总数 = 10 + 4 + 1 = 15.
|
示例 2:
1 2 3 4 5 6 7 8 9 10 11
| 输入:matrix = [ [1,0,1], [1,1,0], [1,1,0] ] 输出:7 解释: 边长为 1 的正方形有 6 个。 边长为 2 的正方形有 1 个。 正方形的总数 = 6 + 1 = 7.
|
提示:
- 1 <= arr.length <= 300
- 1 <= arr[0].length <= 300
- 0 <= arr[i][j] <= 1
题解
一道二维前缀和的暴力题
贴两个公式
求和的:
s[i][j]=s[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1]
求子矩阵(x1,y1),(x2,y2):
sum=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
枚举正方形边长即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: int s[500][500]; int countSquares(vector<vector<int>>& g) { int n=g.size(),m=g[0].size(); int ans=0; memset(s,0,sizeof s); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ s[i][j]=g[i-1][j-1]; if(s[i][j]==1) ans++; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=s[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1]; int d=min(n,m); for(int len=2;len<=d;len++){ for(int i=1;i+len-1<=n;i++) for(int j=1;j+len-1<=m;j++) if(s[i+len-1][j+len-1]+s[i-1][j-1]-s[i-1][j+len-1]-s[i+len-1][j-1]==len*len) ans++; } return ans; } };
|
后面放上dp的思路,开一个二维数组,先将i=0和j=0的一行和一列复制到dp数组里,然后我们的转移方程是dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public: int countSquares(vector<vector<int>>& g) { int n=g.size(),m=g[0].size(); vector<vector<int>> dp(n+10,vector<int>(m+10,0)); int ans=0; for(int i=0;i<n;i++) if(g[i][0]) dp[i][0]=1,ans++; for(int i=0;i<m;i++) if(i!=0&&g[0][i]) dp[0][i]=1,ans++; for(int i=1;i<n;i++) for(int j=1;j<m;j++) if(g[i][j]){ dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1; ans+=dp[i][j]; } return ans; } };
|
5278. 分割回文串 III
题目
给你一个由小写字母组成的字符串 s
,和一个整数 k
。
请你按下面的要求分割字符串:
- 首先,你可以将
s
中的部分字符修改为其他的小写英文字母。
- 接着,你需要把
s
分割成 k
个非空且不相交的子串,并且每个子串都是回文串。
请返回以这种方式分割字符串所需修改的最少字符数。
示例 1:
1 2 3
| 输入:s = "abc", k = 2 输出:1 解释:你可以把字符串分割成 "ab" 和 "c",并修改 "ab" 中的 1 个字符,将它变成回文串。
|
示例 2:
1 2 3
| 输入:s = "aabbc", k = 3 输出:0 解释:你可以把字符串分割成 "aa"、"bb" 和 "c",它们都是回文串。
|
示例 3:
1 2
| 输入:s = "leetcode", k = 8 输出:0
|
提示:
- 1 <= k <= s.length <= 100
s
中只含有小写英文字母。
题解
这个题是一个比较经典的动态规划问题,首先我们做一些初始化操作,O(n^2)将每个区间转化成回文串的步数算出来,然后我们开始思考如何DP
首先我们确定dp的状态表示,dp[i][x]表示0~i的子串切分成x个回文串所需要的操作数,那么我们的dp[i][x]可以从dp[j][x-1]+val[j+1][i]转移过来,也就是在0~i之间切一刀,那么前面的dp[j][x-1]我们已经算过了,val[j+1][i]就是前面初始化操作的记录,我们只需要枚举切分点j,取一个最优的切分点使得操作数最少即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Solution { public: int val[200][200],dp[200][200]; void cal(const string& s,int l,int r){ int n=s.length(); if(n==1){ return; } int i=0,j=n-1; while(i<j){ if(s[i]!=s[j]) val[l][r]++; i++,j--; } } int palindromePartition(string s, int k) { int n=s.length(); memset(val,0,sizeof val); memset(dp,0,sizeof dp); for(int i=0;i<n;i++) for(int j=1;i+j-1<n;j++){ cal(s.substr(i,j),i,i+j-1); } memset(dp,0x3f,sizeof dp); for(int i=0;i<n;i++) dp[i][1]=val[0][i]; for(int i=0;i<n;i++) for(int j=0;j<i;j++) for(int x=2;x<=k;x++){ dp[i][x]=min(dp[i][x],dp[j][x-1]+val[j+1][i]); } return dp[n-1][k]; } };
|