版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/90237266
876. 链表的中间结点
给定一个带有头结点 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 :
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 :
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
提示:
1. 给定链表的结点数介于 1 和 100 之间。
思路:求出链表的长度 ;从链表头开始遍历 次到达中间节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
int len = length(head);
for (int i = 1; i <= len/2; ++i) {
head = head->next;
}
return head;
}
int length(ListNode* head) {
int cnt = 0;
while (head) {
cnt++;
head = head->next;
}
return cnt;
}
};
877. 石子游戏
亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 。
游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。
亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。
假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 ,当李赢得比赛时返回 。
示例:
输入:[5,3,4,5]
输出:true
解释:
亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。
假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。
如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。
这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。
提示:
1. 2 <= piles.length <= 500
2. piles.length 是偶数。
3. 1 <= piles[i] <= 500
4. sum(piles) 是奇数。
思路:动态规划。
- 表示从 开始到 ,亚历克斯最多能赢李多少分
- 考虑一个石子,那么亚历克斯得分即为 , 为当前考虑的石子,那么有
- 考虑从 开始后的 个石子,如果亚历克斯选择了第 个石子,那么从 到 个石子,有 ,即为李的最佳选择(李能赢亚历克斯的最大分数),此时亚历克斯最多能赢李的分数即为 ;同理如果亚历克斯选择了第 个石子,即有
- 综合上述两种情况,可得出动态转移方程为:
class Solution {
public:
int dp[505][505]; //表示亚历克斯最多可以赢李的分数
bool stoneGame(vector<int>& piles) {
memset(dp, 0, sizeof(dp));
int n = piles.size();
for (int i = 0; i < n; ++i) {
dp[i][i] = piles[i];
}
for (int len = 1; len < n; ++len) {
for (int i = 0; i < n - len; ++i) {
dp[i][i + len] = max(piles[i] - dp[i + 1][i + len], piles[i + len] - dp[i][i + len - 1]);
}
}
return dp[0][n - 1] > 0;
}
};
878. 第 N 个神奇数字
如果正整数可以被 或 整除,那么它是神奇的。
返回第 个神奇数字。由于答案可能非常大,返回它模 的结果。
示例 :
输入:N = 1, A = 2, B = 3
输出:2
示例 :
输入:N = 4, A = 2, B = 3
输出:6
示例 :
输入:N = 5, A = 2, B = 4
输出:10
示例 :
输入:N = 3, A = 6, B = 4
输出:8
提示:
1. 1 <= N <= 10^9
2. 2 <= A <= 40000
3. 2 <= B <= 40000
思路:刚开始使用栈暴力破解,然后
参考大神做法:二分法寻找值。 为该序列的最小值 , 即为序列可能达到的最大值 , ,那么整个序列的长度可以得出,即为 ( / __ ,即为最小公倍数), / 表示 序列的长度, 表示 序列的长度, 表示两个序列公共元素;
- (1)如果 ,那么
- (2)如果 ,那么判断 是否成立,如果成立则说明最终元素等于 ,退出循环
- (3)如果 ,
- (4)更新 的值, ;
#define ll long long
class Solution {
public:
const int mod = 1e9 + 7;
int nthMagicalNumber(int N, int A, int B) {
ll left = min(A, B), right = min(A, B) * 1ll * N;
ll lcm = A * 1ll * B / __gcd(A, B);
ll ans = -1;
while (left <= right) {
ll mid = (left + right) >> 1;
ll cnt = mid / A + mid / B - mid / lcm;
if (cnt < N) {
left = mid + 1;
}
else {
if (cnt == N && (mid % A == 0 || mid % B == 0)) {
ans = mid;
break;
}
right = mid - 1;
}
}
return ans % mod;
}
};