牛客网

算法周周练

用bitset

题目来源:牛客网 ==》 链接
一共有 n个数,第 i 个数是 x i x_i xi x i x_i xi可以取 [ l i l_i li, r i r_i ri] 中任意的一个值。 S = Σ x i 2 S=\Sigma x_i^2 S=Σxi2,求 S 种类数。
输入描述:第一行一个数 n。 然后 n 行,每行两个数表示 l i l_i li, r i r_i ri
输出描述:输出一行一个数表示答案。
备注:1 ≤ n , l i l_i li , r i r_i ri≤ 100。
优质答案 ==》 链接

#pragma GCC optimize(3,"Ofast","inline") //G++
#include<bits/stdc++.h>
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fcout cout<<setprecision(4)<<fixed
using namespace std;
typedef long long ll;
//======================================
namespace FastIO{
char print_f[105];void read() {}void print() {putchar('\n');}
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth){x = 0;char ch = getchar();ll f = 1;while (!isdigit(ch)){if (ch == '-')f *= -1;ch = getchar();}while (isdigit(ch)){x = x * 10 + ch - 48;ch = getchar();}x *= f;read(oth...);}
template <typename T, typename... T2>
inline void print(T x, T2... oth){ll p3=-1;if(x<0) putchar('-'),x=-x;do{print_f[++p3] = x%10 + 48;}while(x/=10);while(p3>=0) putchar(print_f[p3--]);putchar(' ');print(oth...);}} // namespace FastIO
using FastIO::print;
using FastIO::read;
//======================================
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn = 1e6+5;
bitset<1000005>pre,ans;
int main() {
#ifndef ONLINE_JUDGE
    freopen("H:\\code\\in.in", "r", stdin);
    freopen("H:\\code\\out.out", "w", stdout);
    clock_t c1 = clock();
#endif
//**************************************
    int n;
    read(n);
    pre[0]=1;
    for(int i=1;i<=n;i++){
        int l,r;
        read(l,r);
        ans.reset();
        for(int i=l;i<=r;i++){
            ans|=pre<<(i*i);
        }
        pre=ans;
    }
    print(ans.count());
//**************************************
     
#ifndef ONLINE_JUDGE
    cerr << "Time:" << clock() - c1 << "ms" << endl;
#endif
    return 0;
}

力扣leetcode

#1 两数之和

(暴力循环 ,map,最优解) ==》链接

暴力循环:执行用时:736 ms(defeat11.09%),内存消耗:7.2 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        vector<int> res;
        for(int i=0;i<n-1;i++){
            for(int j=i+1;j<n;j++){
                if(nums[i]+nums[j]==target){
                    res.push_back(i);
                    res.push_back(j);
                }
            }
        }
        return res;
    }
};

使用map:执行用时:24 ms(defeat52.7%),内存消耗:8.2 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        map<int,int> mp;
        vector<int> res;
        for(int i=0;i<n;i++){
            int t=target-nums[i];
            if(mp.count(t)){
                res.push_back(mp[t]);
                res.push_back(i);
                break;
            }
            else mp[nums[i]]=i;
        }
        return res;
    }
};

网站最优解:执行用时:12 ms(defeat85.62%),内存消耗:8 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        if(nums.size()<=1)
            return res;
        unordered_map<int,int> myMap;
        for(int i=0;i<nums.size();i++){
            int rest_val=target-nums[i];
            if(myMap.find(rest_val)!=myMap.end()){
                int index=myMap[rest_val];
                if(index==i)
                    continue;
                if(index<i){
                    res.push_back(index);
                    res.push_back(i);
                    return res;
                }else{
                    res.push_back(i);
                    res.push_back(index);
                    return res;
                }
            }
            myMap[nums[i]]=i;
        }
        return res;
    }
};

#2 两数相加

(链表,考虑进位) ==》链接

链表操作:执行用时:28 ms(defeat69.2%),内存消耗:9.3MB(defeat100%)

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head=new ListNode(-1);//存放结果的链表
        ListNode* h=head;//移动指针
        int sum=0;//每个位的加和结果
        bool carry=false;//进位标志
        while(l1!=NULL||l2!=NULL){
            sum=0;
            if(l1!=NULL){
                sum+=l1->val;
                l1=l1->next;
            }
            if(l2!=NULL){
                sum+=l2->val;
                l2=l2->next;
            }
            if(carry) sum++;
            h->next=new ListNode(sum%10);
            h=h->next;
            carry=sum>=10?true:false;
        }
        if(carry) h->next=new ListNode(1);
        return head->next;
    }
};

#3 无重复字符的最长子串

(哈希集合 hash set,256字符数组,动态规划) ==》 链接

哈希集合 hash set:执行用时:60 ms(defeat27%),内存消耗:11.3MB(defeat39.7%)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;
    }
};

256字符数组:执行用时:8 ms(defeat93.02%),内存消耗:8.5MB(defeat100%)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int start = 0, n = s.size();
        vector<int> pos(256, -1);
        int res = 0;
        for(int i = 0; i < n; ++i){
            if(pos[s[i]] >= start) start = pos[s[i]] + 1;
            pos[s[i]] = i;
            res = max(res, i - start + 1);
        }
        return res;
    }
};

动态规划:执行用时:8 ms(defeat93.02%),内存消耗:7.1MB(defeat100%)

动态规划解法解题思路:
状态:
dp[i]表示以第i个字符结尾的无重复字符子串的长度。
比如 abcbc :
dp[0] = 1; “a”
dp[1] = 2; “ab”
dp[2] = 3; “abc”
dp[3] = 2; “cb”
dp[4] = 2; “bc”
初始值:对于第一个字符,dp[0] = 1
状态转移:
对于第i个字符,如果在dp[i-1]所代表的子串中出现,那么从所出现的位置j的下一个位置到i,构成了以i结尾的不重复子串。即dp[i] = i-j;
如果第i个字符不在前面的dp[i-1]子串中出现,那么i-1子串加上i字符构成了i子串,因此 dp[i] = dp[i-1]+1;
那么需要担心j位置后又出现了字符i吗?不需要,因为前面的子串本身就是不重复的,不可能存在两个字符i。
最大值: 返回 max(dp[i]) 即可

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int size = (int)s.size();
        if(size==0){
            return 0;
        }
        int lastLen = 1;
        int max = 1;
        int curLen = 0;
        for(int i=1; i<size; ++i){
            curLen = 0;
            for(int j=i-lastLen; j<=i-1; ++j){
                if(s[j]==s[i]){
                    curLen = i-j;
                    break;
                }
            }
            if(curLen==0){
                curLen = lastLen + 1;
            }
            if(curLen>max){
                max = curLen;
            }
            lastLen = curLen;
        }
        return max;
    }
};