classSolution{ public: boolisPalindrome(int x){ if(x < 0 || (x/10 == 0 && x != 0)){ returnfalse; } int revertedNumber = 0; while (x > revertedNumber){ revertedNumber = revertedNumber * 10 + x%10; x /= 10; } return x == revertedNumber || x == revertedNumber/10 //若x有奇数个数字,则中间一位并不影响回文数的性质,去掉中间一位即可 } }
多数元素
给定一个大小为 n 的数组 nums
,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
思路:摩尔投票法
核心理念为票数正负抵消。
在本题中,假设数组长度为n,数组的众数为x。
推论一:若记众数的票数为+1,非众数的票数为-1,则所有数字的和一定>0。
推论二:若数组前a个数票数和为0,则剩余(n-a)个数字的众数仍为x。
根据以上推论,当发生票数和=0的时候,剩余数组的众数一定不变,因为:
若 \(n_1\) =
x,则已经遍历过的数组中有一半是众数。
若 \(n_1\) !=
x,则所有抵消过的数字中众数的个数最小是0个,最大是一半。
即按照以上推论,每次出现票数和为零都可以缩小搜索范围,直到遍历完成,最后一个假定的数字即为众数。
多数元素
1 2 3 4 5 6 7 8 9 10 11
classSolution { public: intmajorityElement(vector<int>& nums){ int x = 0, votes = 0; for (int num : nums){ if (votes == 0) x = num;//当票数和为零的时候假设当前数字为众数 votes += num == x ? 1 : -1; } return x; } };
classSolution { public: intcountRangeSumRecursive(vector<long>& sum, int lower, int upper, int left, int right){ if (left == right) { return0; } else { int mid = (left + right) / 2; int n1 = countRangeSumRecursive(sum, lower, upper, left, mid); int n2 = countRangeSumRecursive(sum, lower, upper, mid + 1, right); int ret = n1 + n2;
// 首先统计下标对的数量 int i = left; int l = mid + 1; int r = mid + 1; while (i <= mid) { while (l <= right && sum[l] - sum[i] < lower) l++; while (r <= right && sum[r] - sum[i] <= upper) r++; ret += (r - l); i++; }
// 随后合并两个排序数组 vector<long> sorted(right - left + 1); int p1 = left, p2 = mid + 1; int p = 0; while (p1 <= mid || p2 <= right) { if (p1 > mid) { sorted[p++] = sum[p2++]; } elseif (p2 > right) { sorted[p++] = sum[p1++]; } else { if (sum[p1] < sum[p2]) { sorted[p++] = sum[p1++]; } else { sorted[p++] = sum[p2++]; } } } for (int i = 0; i < sorted.size(); i++) { sum[left + i] = sorted[i]; } return ret; } }
intcountRangeSum(vector<int>& nums, int lower, int upper){ long s = 0; vector<long> sum{0}; for(auto& v: nums) { s += v; sum.push_back(s); } returncountRangeSumRecursive(sum, lower, upper, 0, sum.size() - 1); } };
最大装水
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i
条线的两个端点是 (i, 0) 和 (i, height[i]) 。
给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个
不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k
。如果存在,返回 true ;否则,返回 false 。
思路:滑动窗口
由于只需要判断在k范围内是否存在重复元素,故可以使用滑动窗口限制比较的元素的数量。
滑动窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { public: boolcontainsNearbyDuplicate(vector<int>& nums, int k){ unordered_set<int> s; int length = nums.size(); for (int i = 0; i < length; i++) { if (i > k) { s.erase(nums[i - k - 1]); } if (s.count(nums[i])) {//计算出现的次数 returntrue; } s.emplace(nums[i]);//将元素添加到队列末尾 } returnfalse; } };
int n, m; int a[maxn]; intcheck(int x){ int cut = 1; int s = a[1]; for (int i = 2; i <= n; i++) { if (s + a[i] <= x) s += a[i]; else { s = a[i]; cut++; } } return cut; } intbin_search(int l, int r){ while (l < r) { int mid = l + (r - l) / 2; if (check(mid) <= m) { r = mid; } else { l = mid + 1; } } return l; } intmain(){ int t; ll mx, sum; cin >> t; while (t--) { mx = 0, sum = 0; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; sum += a[i]; if (mx < a[i]) mx = a[i]; } int ans = bin_search(mx, sum);
defmin_difference_partition(nums): total_sum = sum(nums) n = len(nums) half_total = total_sum // 2 # Initialize dp array dp = [[False] * (half_total + 1) for _ inrange(n + 1)] dp[0][0] = True # Include/Exclude array to keep track of partition include = [[False] * (half_total + 1) for _ inrange(n + 1)] # Fill dp array for i inrange(1, n + 1): for j inrange(half_total + 1): if j >= nums[i-1]: dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i-1]] include[i][j] = include[i-1][j] if dp[i-1][j] else include[i-1][j-nums[i-1]] else: dp[i][j] = dp[i-1][j] include[i][j] = include[i-1][j] # Find the maximum sum that can be achieved up to half_total max_sum = 0 for j inrange(half_total, -1, -1): if dp[n][j]: max_sum = j break # Trace back to find the partition partition1 = [] partition2 = nums[:] current_sum = max_sum for i inrange(n, 0, -1): if include[i][current_sum]: partition1.append(nums[i-1]) current_sum -= nums[i-1] else: partition2.remove(nums[i-1]) # Calculate results n1, n2 = len(partition1), len(partition2) S1, S2 = sum(partition1), sum(partition2) # Optionally, further adjust to balance n1 and n2 if needed # This is an NP-hard problem in general, but here we can do some greedy adjustments # if possible to minimize |n1 - n2| while keeping |S1 - S2| small. # However, since we already balanced S1 and S2 optimally, we focus on the best we found. return partition1, partition2, n1, n2, S1, S2
N皇后问题
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和
'.' 分别代表了皇后和空位。
classSolution: deffindMinArrowShots(self, points: List[List[int]]) -> int: points.sort(key=lambda p: p[1]) # 按照右端点从小到大排序 ans = 0 pre = -inf for start, end in points: if start > pre: # 上一个点在区间左边 ans += 1 pre = end # 在区间的最右边放一个点 return ans
classSolution: deflemonadeChange(self, bills: List[int]) -> bool: five = ten = 0 for b in bills: if b == 5: # 无需找零 five += 1 elif b == 10: # 返还 5 five -= 1 ten += 1 elif ten: # 此时 b=20,返还 10+5 five -= 1 ten -= 1 else: # 此时 b=20,返还 5+5+5 five -= 3 if five < 0: # 无法正确找零 returnFalse returnTrue