赞
踩
- int gcd(int a, int b){
- return b == 0? a: gcd(b, a%b);
- }
- int lcm(int a, int b){
- return a / gcd(a, b) * b;
- }
进一步地,我们也可以通过扩展欧几里得算法(extended gcd)在求得 a 和 b 最大公因数的同时,也得到它们的系数 x 和 y,从而使 ax + by = gcd(a, b)。
- int xGCD(int a,int b, int &x, int &y){
- if(!b){
- x = 1, y = 0;
- return a;
- }
- int x1, y1,;
- int gcd = xGCD(b, a%b, x1, y1);
- x = y1, y = x1 - (a / b) * y1;
- return gcd;
- }
埃拉托斯特尼筛法(Sieve of Eratosthenes ,简称埃氏筛法)是非常常用的,判断一个整数是否是质数的方法。并且它可以在判断一个整数 n 时,同时判断所小于 n 的整数,因此非常适合这道题。其原理也十分易懂:从 1 到 n 遍历,假设当前遍历到 m ,则把所有小于 n 的、且是 m 的倍数的整数标为和数;遍历完成后,没有被标为和数的数字即为质数。
给定整数 n
,返回 所有小于非负整数 n
的质数的数量 。
- class Solution {
- public:
- int countPrimes(int n) {
- if(n <= 2) return 0;
- vector<bool> prime(n, true);
- int count = n - 2;
- for(int i=2; i<n; ++i){
- if(prime[i]){
- for(int j=2*i; j<n; j+=i){
- if(prime[j]){
- prime[j] = false;
- --count;
- }
- }
- }
- }
- return count;
- }
- };
利用质数的一些性质,我们可以进一步优化该算法。
- class Solution {
- public:
- int countPrimes(int n) {
- if(n <= 2) return 0;
- vector<bool> prime(n, true);
- int count = n / 2; // 所有的偶数一定不是质数
- int i = 3, sqrtn = sqrt(n);
- while(i <= sqrtn){ // 最小质因子一定小于等于开方数
- for(int j=i*i; j<n; j+=2*i){ // 避免偶数和重复遍历
- if(prime[j]){
- prime[j] = false;
- --count;
- }
- }
- do{
- i += 2;
- }while(i <= sqrtn && !prime[i]); // 避免偶数和重复遍历
- }
- return count;
- }
- };
给定一个整数 num
,将其转化为 7 进制,并以字符串形式输出。
进制转换类型的题,通常是利用除法和取模(mod )来进行计算,同时也要注意一些细节,如 负数和零。如果输出是数字类型而非字符串,则也需要考虑是否会超出整数上下界。
- class Solution {
- public:
- string convertToBase7(int num) {
- if(num == 0) return "0";
- bool is_negative = num < 0;
- if(is_negative) num = -num;
- string ans;
- while(num){
- int a = num / 7, b = num % 7;
- ans = to_string(b) + ans;
- num = a;
- }
- return is_negative? "-" + ans: ans;
- }
- };
172. Factorial Trailing Zeroes
给定一个整数 n
,返回 n!
结果中尾随零的数量。
提示 n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
每个尾部的 0 由 2 × 5 = 10 而来,因此我们可以把阶乘的每一个元素拆成质数相乘,统计有多少个 2 和 5 。明显的,质因子 2 的数量远多于质因子 5 的数量,因此我们可以只统计阶乘结果里有多少个质因子 5 。
- class Solution {
- public:
- int trailingZeroes(int n) {
- if(n == 0) return 0;
- return n / 5 + trailingZeroes(n / 5);
- }
- };
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
- class Solution {
- public:
- string addStrings(string num1, string num2) {
- string output("");
- reverse(num1.begin(), num1.end());
- reverse(num2.begin(), num2.end());
- int onelen = num1.length(), twolen = num2.length();
- if(onelen <= twolen){
- swap(num1, num2);
- swap(onelen, twolen);
- }
- int addbit = 0;
- for(int i=0; i<twolen; ++i){
- int cur_sum = (num1[i] - '0') + (num2[i] - '0') + addbit;
- output += to_string((cur_sum) % 10);
- addbit = cur_sum < 10? 0: 1;
- }
- for(int i=twolen; i<onelen; ++i){
- int cur_sum = (num1[i] - '0') + addbit;
- output += to_string((cur_sum) % 10);
- addbit = cur_sum < 10? 0: 1;
- }
- if(addbit){
- output += "1";
- }
- reverse(output.begin(), output.end());
- return output;
- }
- };
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3^x
有两种方法,一种是利用对数。设 ,如果 n 是 3 的整数次方,那么 m 一定是整数。
- class Solution {
- public:
- bool isPowerOfThree(int n) {
- return fmod(log10(n) / log10(3), 1) == 0;
- }
- };
另一种方法是,因为在 int 范围内 3 的最大次方是 3^ 19 = 1162261467 ,如果 n 是 3 的整数次方,那么 1162261467 除以 n 的余数一定是零;反之亦然。
- class Solution {
- public:
- bool isPowerOfThree(int n) {
- return n > 0 && 1162261467 % n == 0;
- }
- };
给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。
实现 Solution class:
Solution(int[] nums) 使用整数数组 nums 初始化对象
int[] reset() 重设数组到它的初始状态并返回
int[] shuffle() 返回数组随机打乱后的结果
我们采用经典的 Fisher-Yates 洗牌算法,原理是通过随机交换位置来实现随机打乱,有正向和反向两种写法,且实现非常方便。注意这里“reset ”函数以及类的构造函数的实现细节。
- class Solution {
- public:
- vector<int> origin;
- Solution(vector<int>& nums): origin(std::move(nums)) {
-
- }
-
- vector<int> reset() {
- return origin;
- }
-
- vector<int> shuffle() {
- if(origin.empty()) return {};
- vector<int> shuffled(origin);
- int n = origin.size();
- //反向洗牌
- for(int i=n-1; i>=0; --i){
- swap(shuffled[i], shuffled[rand() % (i + 1)]);
- }
- //正向洗牌
- // for(int i=0; i<n; ++i){
- // int pos = rand() % (n - i);
- // swap(shuffled[i], shuffled[i + pos]);
- // }
- return shuffled;
- }
- };
-
- /**
- * Your Solution object will be instantiated and called as such:
- * Solution* obj = new Solution(nums);
- * vector<int> param_1 = obj->reset();
- * vector<int> param_2 = obj->shuffle();
- */
给你一个 下标从 0 开始 的正整数数组 w ,其中 w[i] 代表第 i 个下标的权重。
请你实现一个函数 pickIndex ,它可以 随机地 从范围 [0, w.length - 1] 内(含 0 和 w.length - 1)选出并返回一个下标。选取下标 i 的 概率 为 w[i] / sum(w) 。
例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。
我们可以先使用 partial_sum 求前缀和(即到每个位置为止之前所有数字的和),这个结果对于正整数数组是单调递增的。每当需要采样时,我们可以先随机产生一个数字,然后使用二分法查找其在前缀和中的位置,以模拟加权采样的过程。这里的二分法可以用 lower_bound 实现。以样例为例,权重数组[1,3] 的前缀和为 [1,4] 。如果我们随机生成的数字为 1 ,那么 lower_bound 返回的位置为 0 ;如果我们随机生成的数字是 2 、 3 、 4 ,那么 lower_bound 返回的位置为 1 。关于前缀和的更多技巧,我们将在接下来的章节中继续深入讲解。
- class Solution {
- public:
- vector<int> sums;
- Solution(vector<int>& w): sums(std::move(w)) {
- partial_sum(sums.begin(), sums.end(), sums.begin());
- }
-
- int pickIndex() {
- int pos = (rand() % sums.back()) + 1;
- return lower_bound(sums.begin(), sums.end(), pos) - sums.begin();
- }
- };
-
- /**
- * Your Solution object will be instantiated and called as such:
- * Solution* obj = new Solution(w);
- * int param_1 = obj->pickIndex();
- */
给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。
实现 Solution 类:
Solution(ListNode head) 使用整数数组初始化对象。
int getRandom() 从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。
不同于数组,在未遍历完链表前,我们无法知道链表的总长度。这里我们就可以使用水库采样:遍历一次链表,在遍历到第 m 个节点时,有 的概率选择这个节点覆盖掉之前的节点选择。我们提供一个简单的,对于水库算法随机性的证明。对于长度为 n 的链表的第 m 个节点,最 后被采样的充要条件是它被选择,且之后的节点都没有被选择。这种情况发生的概率为 。因此每个点都有均等的概率被选择。
- /**
- * Definition for singly-linked list.
- * struct ListNode {
- * int val;
- * ListNode *next;
- * ListNode() : val(0), next(nullptr) {}
- * ListNode(int x) : val(x), next(nullptr) {}
- * ListNode(int x, ListNode *next) : val(x), next(next) {}
- * };
- */
- class Solution {
- public:
- ListNode* head;
- Solution(ListNode* n): head(n) {
-
- }
-
- int getRandom() {
- int ans = head->val;
- ListNode* node = head->next;
- int i = 2;
- while(node){
- if((rand() % i) == 0){
- ans = node->val;
- }
- ++i;
- node = node->next;
- }
- return ans;
- }
- };
-
- /**
- * Your Solution object will be instantiated and called as such:
- * Solution* obj = new Solution(head);
- * int param_1 = obj->getRandom();
- */
238. Product of Array Except Self
462. Minimum Moves to Equal Array Elements II
470. Implement Rand10() Using Rand7()
欢迎大家共同学习和纠正指教
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。