Leetcode 之旅(简单题51-100)

有效电话号码

给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个 bash 脚本输出所有有效的电话号码。

grep -E "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$|^[0-9]{3}-[0-9]{3}-[0-9]{4}$"  file.txt

执行用时 : 20 ms, 在Valid Phone Numbers的Bash提交中击败了25.55% 的用户
内存消耗 : 3.1 MB, 在Valid Phone Numbers的Bash提交中击败了100.00% 的用户

第十行

给定一个文本文件 file.txt,请只打印这个文件中的第十行。

sed -n “3p” filename #输出文件的第3行 
sed -n “2,5p“ filename #输出文件的第2到5行 
sed ”/abc/d“ filename #删除包含“abc”的行 
sed “2d” filename #删除第2行 
sed ”$d“ filename #删除最后一行
cat file.txt|sed -n "10p"

执行用时 : 12 ms, 在Tenth Line的Bash提交中击败了28.33% 的用户
内存消耗 : 3.7 MB, 在Tenth Line的Bash提交中击败了100.00% 的用户

删除重复的电子邮箱

编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。

DELETE p1  
FROM Person p1, Person p2  
WHERE p1.Email = p2.Email AND  
p1.Id > p2.Id

select 了我半天
直接创建了个表啊
这是百度学会的orz

上升的温度

给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 Id。

可以用weather创建两个表进行比较

select w1.Id from Weather w1, Weather w2
    where w1.Temperature > w2.Temperature
    and  DATEDIFF(w1.RecordDate, w2.RecordDate) = 1

DATEDIFF(D1, D2)

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

到C++了呀,感觉写sql和shell还挺过瘾

动态规划,到第i家偷窃的金额: f ( i ) = m a x f ( i − 1 ) , f ( i − 2 ) + i , f ( i − 3 ) + i f(i) = max{ f(i-1), f(i-2)+ i, f(i-3)+i} f(i)=maxf(i1),f(i2)+i,f(i3)+i

class Solution {
public:
    int rob(vector<int>& nums) {
        int l = nums.size();
        if(l<=0)    return 0;
        if(l==1)    return nums[0];
        if(l==2)    return max(nums[1], nums[0]);
        if(l==3)    return max(nums[0]+nums[2], nums[1]);
        vector<int> money;
        money.push_back(nums[0]);
        money.push_back(max(nums[1], nums[0]));
        money.push_back(max(nums[0]+nums[2], nums[1]));
    
        for(int i=3; i<l; i++)
        {
            int a = money[i-2]+nums[i];
            int b = money[i-3]+ nums[i];
            money.push_back(max(money[i-1],max(a, b)));
        }
        return money[l-1];
    }
};

第一次老提交发现缓冲区溢出,后来发现是没有判断l=1,2,3的问题

执行用时 : 12 ms, 在House Robber的C++提交中击败了13.40% 的用户
内存消耗 : 9 MB, 在House Robber的C++提交中击败了0.94% 的用户

快乐数

编写一个算法来判断一个数是不是“快乐数”。
一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

bool isHappy(int n) {
    vector<int> number;
    bool happy = false;
    number.push_back(n);
    
    while(!happy)
    {
        
        int tmp = 0;
        while(n > 0)
        {
            tmp += pow(n%10, 2);
            n = n/10;
        }
        
        if(tmp == 1)
        {
            happy = true;
        }
        else if (count(number.begin(), number.end(), tmp))
            break;
        number.push_back(tmp);
        n = tmp;
        
    }
    return happy;
}

找规律,对于每次出现的数,存于一个vector,如果重复出现,则陷入循环。

移除链表元素

删除链表中等于给定值 val 的所有节点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        
        while(head!=nullptr && head->val == val) head = head->next;
        
        if(head == nullptr)  return head;
        ListNode *p = head;
        while(p->next !=nullptr)
        {
            if(p->next->val == val) 
            {
                    p->next = p->next->next;
            }
            else p = p->next;
        }
        return head;

    }
};

执行用时 : 48 ms, 在Remove Linked List Elements的C++提交中击败了3.07% 的用户
内存消耗 : 11.3 MB, 在Remove Linked List Elements的C++提交中击败了0.72% 的用户

p++了半天,哭了

计数质数

统计所有小于非负整数 n 的质数的数量。

埃拉托斯特尼筛法 Sieve of Eratosthenes

class Solution {
public:
    int countPrimes(int n) {
        if(!n||n==1)  return 0;
        vector<bool> isPrime(n,true);

        for(int i=2;i*i<n;++i)
        {
            if(!isPrime[i]) continue;
            //填表起点i*i,如3*3,因为3*2已填,步长+i
            **for(int j=i*i;j<n;j+=i)**
            {
                isPrime[j]=false;
            }
        }
        int count=0;
        for(int i=2;i<n;++i)
        {
            if(isPrime[i])  ++count;
        }
        return count;
    }
};

详细代码, 参考Count Primes 计数质数

执行用时 : 244 ms, 在Count Primes的C++提交中击败了32.89% 的用户
内存消耗 : 8.7 MB, 在Count Primes的C++提交中击败了17.54% 的用户

同构字符串

给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

采取map字典的方式,每读一对存入,要注意地是判断:

  1. 原映射对是否匹配?
  2. 不存在映射对时,判断新映射对是否存在多对一的情况
bool isIsomorphic(string s, string t) {
    map<char, char>Alpha;
    int m = s.length();
    int n = t.length();
    if(m!=n) return false;
    Alpha[s[0]] = t[0];
    for(int i=1; i<m; i++)
    {
        if(Alpha.count(s[i])==0)
        {
            
            map<char, char>::iterator iter;
            iter = Alpha.begin();
            while(iter != Alpha.end()) {
                if(iter->second != t[i])
                    iter++;
                else return false;
            }
            Alpha[s[i]] = t[i];
        }
        else if(Alpha[s[i]] != t[i] )
            return false;
    }
    return true;
}

执行用时 : 16 ms, 在Isomorphic Strings的C++提交中击败了27.49% 的用户
内存消耗 : 9.1 MB, 在Isomorphic Strings的C++提交中击败了0.54% 的用户

反转链表

反转一个单链表

用栈老超时

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return head;
        ListNode *p, *q, *r;
        p= head;
        q = p->next;
        head->next = NULL;
        while(q!=NULL)
        {
            r = q->next;
            q->next = p;
            p = q;
            q = r;
        }
        head = p;
        return head;
    }
};

执行用时 : 24 ms, 在Reverse Linked List的C++提交中击败了9.24% 的用户
内存消耗 : 9.2 MB, 在Reverse Linked List的C++提交中击败了0.86% 的用户

存在重复元素

给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。


bool containsDuplicate(vector<int>& nums) {
    int l = nums.size();
    unordered_map<int, int> cmp;
    for (int i = 0; i < nums.size(); i++)
    {
        if (cmp.find(nums[i]) == cmp.end())
        {
            cmp.insert({nums[i], i});
        }
        else
        {
            if (i - cmp[nums[i]] <= l)
            {
                return true;
            }
            else
            {
                cmp[nums[i]] = i;
            }
        }
    }
    return false;
    
}

执行用时 : 84 ms, 在Contains Duplicate的C++提交中击败了10.51% 的用户
内存消耗 : 16.4 MB, 在Contains Duplicate的C++提交中击败了0.92% 的用户

考察哈希表:
STL中,map 对应的数据结构是 红黑树。红黑树是一种近似于平衡的二叉查找树,里面的数据是有序的。在红黑树上做查找操作的时间复杂度为 O(logN)。而 unordered_map 对应 哈希表,哈希表的特点就是查找效率高,时间复杂度为常数级别 O(1), 而额外空间复杂度则要高出许多。所以对于需要高效率查询的情况,使用 unordered_map 容器。而如果对内存大小比较敏感或者数据存储要求有序的话,则可以用 map 容器。

存在重复元素 II

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k。

bool containsNearbyDuplicate(vector<int>& nums, int k) {
    unordered_map<int, int> hs;
    for(int i=0; i<nums.size(); i++)
    {
        if(hs.find(nums[i]) == hs.end())
        {
            hs.insert({nums[i], i});
        }
        else
        {
            if(i-hs[nums[i]] <=k)
            {
                return true;
            }
            else
            {
                hs[nums[i]] =i;
            }
            
        }
    }
    return false;
}

emmm,我把上一道题抄错了 = =

执行用时 : 92 ms, 在Contains Duplicate II的C++提交中击败了16.35% 的用户
内存消耗 : 15.3 MB, 在Contains Duplicate II的C++提交中击败了0.98% 的用户

用队列实现栈

使用队列实现栈的下列操作:
-push(x) – 元素 x 入栈
-pop() – 移除栈顶元素
-top() – 获取栈顶元素
-empty() – 返回栈是否为空

class MyStack {
public:
    queue<int> Q1;
    queue<int> Q2;
    
    /** Initialize your data structure here. */
    MyStack() {
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        if(!Q1.empty())
        {
            Q2.push(Q1.front());
            Q1.pop();
        }
        Q1.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        if(Q1.empty() && Q2.empty())
        {
            throw 1;
        }
        int top = 0;
        if(!Q2.empty() && Q1.empty())
        {
            while(Q2.size() > 1)
            {
                Q1.push(Q2.front());
                Q2.pop();
            }
            top = Q2.front();
            Q2.pop();
        }
        else if(!Q1.empty())
        {
            while(Q1.size() > 1)
            {
                Q2.push(Q1.front());
                Q1.pop();
            }
            top = Q1.front();
            Q1.pop();
            
        }
        return top;
    }
    
    /** Get the top element. */
    int top() {
        if(Q1.empty() && Q2.empty())
        {
            throw 1;
        }
        int top = 0;
        if(!Q2.empty() && Q1.empty())
        {
            while(Q2.size() > 1)
            {
                Q1.push(Q2.front());
                Q2.pop();
            }
            top = Q2.front();
            Q1.push(top);
            Q2.pop();
        }
        else if(!Q1.empty())
        {
            while(Q1.size() > 1)
            {
                Q2.push(Q1.front());
                Q1.pop();
            }
            top = Q1.front();
            
        }
        return top;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        if(Q1.empty() && Q2.empty())
            return true;
        else return false;
    }
};

执行用时 : 8 ms, 在Implement Stack using Queues的C++提交中击败了21.07% 的用户
内存消耗 : 9 MB, 在Implement Stack using Queues的C++提交中击败了0.78% 的用户

翻转二叉树

翻转一棵二叉树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==nullptr) return nullptr;
        TreeNode *tmp;
        tmp = root->left;
        root->left = root->right;
        root->right = tmp;
        invertTree(root->left);
        invertTree(root->right);
        return root;
        
        
    }
};

执行用时 : 12 ms, 在Invert Binary Tree的C++提交中击败了11.63% 的用户
内存消耗 : 9 MB, 在Invert Binary Tree的C++提交中击败了0.95% 的用户

2的幂

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n<=0)    return false;
    if(n==1)    return true;
    while(n>1)
    {
        if(n%2 == 1) return false;
        n = n/2;
    }
    return true;
    }
};

执行用时 : 12 ms, 在Power of Two的C++提交中击败了13.06% 的用户
内存消耗 : 7.9 MB, 在Power of Two的C++提交中击败了0.36% 的用户

二进制来做,高位为1其他位为0即为2的次幂方

用栈实现队列

使用栈实现队列的下列操作:

  • push(x) – 将一个元素放入队列的尾部。
  • pop() – 从队列首部移除元素。
    -peek() – 返回队列首部的元素。
    -empty() – 返回队列是否为空。

class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int> S1;
    stack<int> S2;
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        S1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int top = 0;
        if(S1.empty() &&  S2.empty())
            throw "The queue is empty.";
        if(!S2.empty())
        {
            top = S2.top();
            S2.pop();
        }
        else
        {
            while(!S1.empty())
            {
                S2.push(S1.top());
                S1.pop();
            }
            top = S2.top();
            S2.pop();
        }
        return top;
    }
    
    /** Get the front element. */
    int peek() {
        int top = 0;
        if(S1.empty() &&  S2.empty())
            throw "The queue is empty.";
        if(!S2.empty())
        {
            top = S2.top();
        }
        else
        {
            while(!S1.empty())
            {
                S2.push(S1.top());
                S1.pop();
            }
            top = S2.top();
        }
        return top;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if(S1.empty() && S2.empty())
            return true;
        
        else return false;
    }
};

执行用时 : 8 ms, 在Implement Queue using Stacks的C++提交中击败了22.68% 的用户
内存消耗 : 8.9 MB, 在Implement Queue using Stacks的C++提交中击败了0.64% 的用户

回文链表

请判断一个链表是否为回文链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == nullptr) return true;
        if(head->next == nullptr) return true;
        int length = 0;
        ListNode *p = head;
        while(p!=nullptr) 
        {
            length ++;
            p = p->next;
        }
        p = head;
        stack<int> s;
        for(int i=0; i<length/2; i++)
        {
            s.push(p->val);
            p = p->next;
        }
        if(length%2==1) p = p->next;
        while(!s.empty())
        {
            if(p->val != s.top())   return false;
            else
            {
                p = p->next;
                s.pop();
            }
        }
        return true;
    }
};

用了栈,但是空间复杂度就上了

由于单链表只能从前往后遍历,因此要想实现空间复杂度为常数,思路就是将后半部分链表给逆序了。这样的话,一个指针从前半段链表的head开始从前往后走,另一个指针从后半段链表的head开始从后往前走,挨个比较即可。

二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr|| root==p || root==q)   return root;
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
        if(left != nullptr && right !=nullptr)
            return root;
        if(left==nullptr)  return right;
        else return left;
    }
};

执行用时 : 64 ms, 在Lowest Common Ancestor of a Binary Search Tree的C++提交中击败了0.98% 的用户
内存消耗 : 25.7 MB, 在Lowest Common Ancestor of a Binary Search Tree的C++提交中击败了0.80% 的用户

删除链表中的节点

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

head呢?这个题有毒

``c++
/**

  • Definition for singly-linked list.
  • struct ListNode {
  • int val;
    
  • ListNode *next;
    
  • ListNode(int x) : val(x), next(NULL) {}
    
  • };
    /
    class Solution {
    public:
    void deleteNode(ListNode
    node) {
    *node = *(node->next);
    }
    };

执行用时 : 24 ms, 在Delete Node in a Linked List的C++提交中击败了9.34% 的用户
内存消耗 : 9.2 MB, 在Delete Node in a Linked List的C++提交中击败了0.57% 的用户

## 有效的字母异位词
> 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。

我这个办法好笨啊

```c++
class Solution {
public:
    bool isAnagram(string s, string t) {
            int m = s.size();
    int n = t.size();
    if(m!=n) return false;
    int count_s[26] = {0};
    int count_t[26] = {0};
    for(int i=0; i<m; i++)
    {
        count_s[s[i] - 'a'] ++;
        count_t[t[i] - 'a'] ++;
    }
    for(int i=0; i<26; i++)
    {
        if(count_s[i] != count_t[i])
            return false;
    }
    return true;
    }
};

执行用时 : 20 ms, 在Valid Anagram的C++提交中击败了38.36% 的用户
内存消耗 : 9.1 MB, 在Valid Anagram的C++提交中击败了0.42% 的用户

二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

vector<string> binaryTreePaths(TreeNode* root) {
    
    vector<string> res;
    
    if(root==nullptr) return res;
    
    if(root->left == nullptr && root-> right == nullptr)
    {
        string s = to_string(root->val);
        res.push_back(s);
        return res;
    }
    
    vector<string> left = binaryTreePaths(root->left);
    for(int i=0; i<left.size(); i++)
    {
        string tmpLeft = to_string(root->val) + "->" + left[i];
        res.push_back(tmpLeft);
    }
    vector<string> right = binaryTreePaths(root->right);
    for(int i=0; i<right.size(); i++)
    {
        string tmpRight = to_string(root->val) + "->" + right[i];
        res.push_back(tmpRight);
    }
    
    return res;   
    
}

执行用时 : 24 ms, 在Binary Tree Paths的C++提交中击败了4.30% 的用户
内存消耗 : 12.9 MB, 在Binary Tree Paths的C++提交中击败了0.67% 的用户

各位相加

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。

做不动啦!回了!

int addDigits(int num) {
    if(num == 0) return 0;
    int res = num%9;
    if(res == 0) return 9;
    else return res;
}

丑数

只有质因子2,3,5

bool isUgly(int num) {
    if(num<=0) return false;
    if(num==1) return true;
    while(num%2==0)
        num = num/2;
    while(num%3==0)
        num = num/3;
    while(num%5==0)
        num = num/5;
    if(num != 1) return false;
    else return true;
}

执行用时 : 8 ms, 在Ugly Number的C++提交中击败了19.07% 的用户
内存消耗 : 8.1 MB, 在Ugly Number的C++提交中击败了0.87% 的用户

缺失数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。

int missingNumber(vector<int>& nums) {
    int n = nums.size();
    vector<int> mark(n+1, 0);
    int i=0;
    for(i=0; i<n; i++)
    {
        mark[nums[i]] = 1;
    }
    for(i=0; i<n+1; i++)
    {
        if(mark[i] == 0)
            return i;
    }
    return i;
}

执行用时 : 48 ms, 在Missing Number的C++提交中击败了5.14% 的用户
内存消耗 : 10.1 MB, 在Missing Number的C++提交中击败了0.92% 的用户

也可用总和-数组和

第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

目的找到第一个是的isBadVersion的i

折半法:mid如果为true,找左部分;负责找右部分的中间值

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        long left = 1; 
        long right = n;
        while(left<right)
        {
            long mid = (left+right)/2;
            if(isBadVersion(mid))
                right = mid;
            else left = mid +1;
        }
        return left;
    }
};

执行用时 : 8 ms, 在First Bad Version的C++提交中击败了18.49% 的用户
内存消耗 : 8.1 MB, 在First Bad Version的C++提交中击败了0.53% 的用户

移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序

void moveZeroes(vector<int>& nums) {
    if(nums.size()<=1)
        return;
    int index = 0;
    int l = nums.size();
    for(int i=0; i<l; i++)
    {
        if(nums[i] !=0)
        {
            nums[index] = nums[i];
            index ++;
        }
    }
    for(;index<l;index++)
        nums[index] = 0;
  
}

执行用时 : 24 ms, 在Move Zeroes的C++提交中击败了22.77% 的用户
内存消耗 : 9.3 MB, 在Move Zeroes的C++提交中击败了0.90% 的用户

单词模式

给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式。

哇这个毫无思路呢

Nim游戏

你和你的朋友,两个人一起玩 Nim游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。
你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。

class Solution {
public:
    bool canWinNim(int n) {
        if((n-1)%4 ==0 || (n-2)%4==0 ||(n-3)%4==0)
        return true;
        else return false;
    }
};

执行用时 : 8 ms, 在Nim Game的C++提交中击败了14.90% 的用户
内存消耗 : 7.9 MB, 在Nim Game的C++提交中击败了0.00% 的用户

解释:
如果堆中有 4 块石头,那么你永远不会赢得比赛;
因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。

区域和检索 - 数组不可变

给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。

= = 这个题给了个 NumArray(vector nums)搞的我不知道它在干什么

class NumArray {
public:
    vector<int>sum;
    NumArray(vector<int> nums) {
        sum.push_back(0);
        for(int i=1; i<=nums.size();i++)
            sum.push_back(sum[i-1]+nums[i-1]);
    }
    
    int sumRange(int i, int j) {
        return sum[j+1]-sum[i];
    }
};

执行用时 : 52 ms, 在Range Sum Query - Immutable的C++提交中击败了90.53% 的用户
内存消耗 : 17.3 MB, 在Range Sum Query - Immutable的C++提交中击败了0.59% 的用户

3的幂

给定一个整数,写一个函数来判断它是否是 3 的幂次方

class Solution {
public:
    bool isPowerOfThree(int n) {
        if(n==0) return false;
        while(n%3==0)
        {
            n = n/3;
        }
        if(n==1) return true;
        else return false;
            
    }
};

执行用时 : 80 ms, 在Power of Three的C++提交中击败了14.61% 的用户
内存消耗 : 8 MB, 在Power of Three的C++提交中击败了0.89% 的用户

非循环的方法嘞?

class Solution {
 public:
  bool isPowerOfThree(int n) {
    // int32 范围内最大的3的幂次
    return n > 0 && 1162261467 % n == 0;
  }
};

4的幂

给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。

class Solution {
public:
    bool isPowerOfFour(int num) {
        if(num<=0) return false;
        int a =(num-1) & num ;
        int b = num & 0x55555555;
        if(a == 0 && b==num )
            return true;
        else return false;
    }
};

找规律,2进制中只有一个1,并且1后面0为偶数个

执行用时 : 8 ms, 在Power of Four的C++提交中击败了18.73% 的用户
内存消耗 : 8 MB, 在Power of Four的C++提交中击败了0.00% 的用户

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

class Solution {
public:
    void reverseString(vector<char>& s) {
        int l = s.size();
        for(int i =0; i<l/2; i++)
        {
            char tmp = s[i];
            s[i] = s[l-i-1];
            s[l-i-1] = tmp;
        
        }
    }
};

执行用时 : 108 ms, 在Reverse String的C++提交中击败了1.41% 的用户
内存消耗 : 17.8 MB, 在Reverse String的C++提交中击败了0.84% 的用户

反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母

class Solution {
public:
    string reverseVowels(string s) {
        vector<char> vowels;
        vowels.push_back('a');
        vowels.push_back('o');
        vowels.push_back('e');
        vowels.push_back('i');
        vowels.push_back('u');
        vowels.push_back('A');
        vowels.push_back('O');
        vowels.push_back('E');
        vowels.push_back('I');
        vowels.push_back('U');
        int i=0, j=s.size()-1;
        while(i<j)
        {
            if(count(vowels.begin(), vowels.end(), s[i])>0 )
            {
                if(count(vowels.begin(), vowels.end(), s[j])>0 )
                {
                    char tmp = s[i];
                    s[i] = s[j];
                    s[j] = tmp;
                    i++;
                    j--;
                }
                else j--;
            }
            else  i++;
        }
        return s;
    }
};

执行用时 : 24 ms, 在Reverse Vowels of a String的C++提交中击败了11.48% 的用户
内存消耗 : 9.6 MB, 在Reverse Vowels of a String的C++提交中击败了0.88% 的用户

两个数组的交集

给定两个数组,编写一个函数来计算它们的交集

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    vector<int>res;
    for(int i=0; i<nums1.size();i++)
    {
        if(count(nums2.begin(), nums2.end(), nums1[i])>=1 && count(res.begin(), res.end(), nums1[i])==0 )
            res.push_back(nums1[i]);
    }
    return res;
}

执行用时 : 40 ms, 在Intersection of Two Arrays的C++提交中击败了1.43% 的用户
内存消耗 : 8.9 MB, 在Intersection of Two Arrays的C++提交中击败了0.52% 的用户

跳着做

有效的完全平方数

给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False

两整数之和

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。

猜数字大小

我们正在玩一个猜数字游戏。 游戏规则如下:
我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。
每次你猜错了,我会告诉你这个数字是大了还是小了。
你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0):

就是变法的折半查找

// Forward declaration of guess API.
// @param num, your guess
// @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
int guess(int num);

class Solution {
public:
    int guessNumber(int n) {
        long left = 1;
        long right = n;
        
        while(left<right)
        {
            long mid = (left + right)/2;
            if(guess(mid) == 0) return mid;
            else if(guess(mid) == -1) right = mid;
            else if(guess(mid) == 1)  left = mid+1;
        }
        return left;
    }
};

执行用时 : 8 ms, 在Guess Number Higher or Lower的C++提交中击败了14.18% 的用户
内存消耗 : 8.1 MB, 在Guess Number Higher or Lower的C++提交中击败了0.90% 的用户

赎金信

给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成。如果可以构成,返回 true ;否则返回 false。

bool canConstruct(string ransomNote, string magazine) {
    for(int i=0; i<ransomNote.length(); i++)
    {
        if(ransomNote.length()==0) return true;
        if(magazine.length() == 0) return false;
        if(ransomNote.length()>magazine.length()) return false;
        int pos = magazine.find(ransomNote[i]);
        if(pos>-1)  magazine.erase(pos, 1);
        else return false;
    }
    return true;
}

执行用时 : 128 ms, 在Ransom Note的C++提交中击败了1.43% 的用户
内存消耗 : 11.6 MB, 在Ransom Note的C++提交中击败了0.00% 的用户

其他做法,借助外部数组

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int abc[26] = {0};
        
        for(int i = 0;i < magazine.size();++i)
        {
            abc[magazine[i] - 'a']++;
        }
        
        for(int i = 0;i < ransomNote.size();++i)
        {
            if (abc[ransomNote[i] - 'a'] == 0)
                return false;
            else
                abc[ransomNote[i] - 'a']--;
        }
        
        return true;
    }
};

字符串中的第一个唯一字符

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1

int firstUniqChar(string s) {
    if(s.empty()) return -1;
    
    vector<int>Alpha(26, -1);
    for(int i=0; i<s.length();i++)
    {
        int pos = s[i] - 'a';
        if(Alpha[pos]==-1) Alpha[pos] = i;
        else if(Alpha[pos]!=-1) Alpha[pos] = -2;
    }
    int MinIndex = s.length();
    for(int i=0; i<26;i++)
    {
        if(Alpha[i]<MinIndex && Alpha[i] >=0)
            MinIndex = Alpha[i];
    }
    if(MinIndex != s.length()) return MinIndex;
    else return -1;
}

执行用时 : 44 ms, 在First Unique Character in a String的C++提交中击败了60.25% 的用户
内存消耗 : 13.4 MB, 在First Unique Character in a String的C++提交中击败了0.93% 的用户

先利用数组,此时每个字符串有三种情况:没有出现,出现一次,出现两次。规定每个一个数值范围,存储下标比较找到最小

找不同

给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。

char findTheDifference(string s, string t) {
    if(s.empty() && t.length() == 1) return t[0];
    char res;
    
    for(int i=0; i<t.length(); i++)
    {
        int pos = s.find(t[i]);
        if(pos == -1)
        {
            res = t[i];
        }
        else s.erase(pos, 1);
        
    }
    return res;
}

执行用时 : 16 ms, 在Find the Difference的C++提交中击败了9.32% 的用户
内存消耗 : 9.2 MB, 在Find the Difference的C++提交中击败了0.00% 的用户

将所给的字符串转换为字符数组,求字符数组的int和,作差,再转回char,返回(3ms,击败100%),也可和上面题一样存一个数组

第N个数字

在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …中找到第 n 个数字

= = 我是笨蛋,想死我了

class Solution {
public:
    int findNthDigit(int n) {
        long long lenOfDit = 1, start = 1, count = 9;
        while (n > lenOfDit*count)
        {
            n -= lenOfDit*count;
            lenOfDit += 1;
            count *= 10;
            start *= 10;
        }

        int num = start + (n - 1) / lenOfDit;
        string s = to_string(num);
        return s[(n - 1) % lenOfDit] - '0';

    }
};

执行用时 : 12 ms, 在Nth Digit的C++提交中击败了13.97% 的用户
内存消耗 : 8.7 MB, 在Nth Digit的C++提交中击败了0.00% 的用户

我们首先来分析自然数序列和其位数的关系,前九个数都是1位的,然后10到99总共90个数字都是两位的,100到999这900个数都是三位的,那么这就很有规律了,我们可以定义个变量cnt,初始化为9,然后每次循环扩大10倍,再用一个变量len记录当前循环区间数字的位数,另外再需要一个变量start用来记录当前循环区间的第一个数字,我们n每次循环都减去len*cnt (区间总位数),当n落到某一个确定的区间里了,那么**(n-1)/len就是目标数字在该区间里的坐标**,加上start就是得到了目标数字,然后我们将目标数字start转为字符串,(n-1)%len就是所要求的目标位,最后别忘了考虑int溢出问题,我们干脆把所有变量都申请为长整型的好了

减1是因为从0开始

正向思维啊!

二进制手表

二进制手表顶部有 4 个 LED 代表小时(0-11),底部的 6 个 LED 代表分钟(0-59)。
每个 LED 代表一个 0 或 1,最低位在右侧。
给定一个非负整数 n 代表当前 LED 亮着的数量,返回所有可能的时间。

排列组合

左叶子之和

计算给定二叉树的所有左叶子之和。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if(root == nullptr) return 0;
        int sum = 0;   
        if(root->left != nullptr && root->left->left == nullptr && root->left->right == nullptr)
            sum = root->left->val + sumOfLeftLeaves(root->left);
        else sum = sumOfLeftLeaves(root->left);
        sum += sumOfLeftLeaves(root->right);
        return sum;
    }
};

执行用时 : 116 ms, 在Sum of Left Leaves的C++提交中击败了0.50% 的用户
内存消耗 : 14 MB, 在Sum of Left Leaves的C++提交中击败了0.00% 的用户

数字转换为十六进制数

给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。
注意:

  • 十六进制中所有字母(a-f)都必须是小写。
  • 十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符’0’来表示;对于其他情况,十六进制字符串中的第一
  • 字符将不会是0字符。
  • 给定的数确保在32位有符号整数范围内。
  • 不能使用任何由库提供的将数字直接转换或格式化为十六进制的方法。
class Solution {
public:
    char ReNum(int num)
    {
        char HexNum[6] = {'a', 'b', 'c', 'd', 'e', 'f'};
        if(num>9)
            return HexNum[num%10];
        else return num + '0';
    }

    string toHex(int num) {
        if(num==0) return "0";
        string res;
        unsigned int n = (unsigned int)num;
        while(n>0)
        {
            res = ReNum(n % 16)+res;
            n =n/16;
        }


    
        return res;
    }
};

执行用时 : 8 ms, 在Convert a Number to Hexadecimal的C++提交中击败了15.27% 的用户
内存消耗 : 8.7 MB, 在Convert a Number to Hexadecimal的C++提交中击败了0.00% 的用户

如果是负数,就直接强制转换为无符号数,直接补码变为无符号数

最长回文串

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。

int longestPalindrome(string s) {
    if(s.length()<=1)  return s.length();
    
    vector<int>Alpha(52, 0);
    for(int i=0; i<s.length();i++)
    {
        if(s[i] >= 'A' && s[i]<='Z')
            Alpha[s[i] - 'A'] +=1;
        else Alpha[s[i] - 'a' + 26] +=1;
    }
    
    bool one = false;
    int count = 0;
    for(int i=0; i<52; i++)
    {
        count += Alpha[i]/2 * 2;
        if(!one && Alpha[i]%2==1)
        {
            one = true;
            count +=1;
        }
    }
    return count;
}

执行用时 : 16 ms, 在Longest Palindrome的C++提交中击败了11.28% 的用户
内存消耗 : 9 MB, 在Longest Palindrome的C++提交中击败了0.00% 的用户

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值