Note
不使用传统的“+”运算符,即十进制下的加法,那就从最基础的二进制加法原理出发。
单独位相加:0 + 0 = 0, 0 + 1 = 1, 1 + 0 = 0, 1 + 1 = 0。
进位:0 + 0 = 0; 0 + 1 = 0; 1 + 0 = 0; 1 + 1 = 1。
可以发现,单独位相加符合异或运算的规则,进位符合与运算的规则。加法的结果 = 单独位 + 进位,因此可以模拟加法运算。由于进位是进到更高位,所以在进位后,要进行一次左移操作,以使进位给到前一位。
class Solution {
public:
/**
* @param a: An integer
* @param b: An integer
* @return: The sum of a and b
*/
int aplusb(int a, int b) {
return (a ^ b) + ((a & b) << 1);
}
};
Note
可以这么理解:比如 2456810000 = 245681 × 10 × 10 × 10 × 10 2456810000 = 245681\times 10\times 10\times 10\times 10 2456810000=245681×10×10×10×10,可以知道,任何一个n的阶乘,其末尾0的个数取决于因数10的个数。而 10 = 2 × 5 10 = 2\times 5 10=2×5,由于2出现的次数要远远大于5,所以我们只需计算n的阶乘的因数中5的个数。这里便能得出一个结论:
n的阶乘的尾部为0的个数主要取决于其中5的个数。
因为 n ! = 1 × 2 × 3 × ⋅ ⋅ ⋅ × ( n − 1 ) × n n! = 1\times 2\times 3\times···\times(n - 1)\times n n!=1×2×3×⋅⋅⋅×(n−1)×n,所以我们最基础的想法就是,枚举1到n,去整除5,能整除计数加1。同时要注意,不是单纯地能整除就行,需要对每个枚举的数都要除5到0为止。比如25是含两个5,所以计数是加2。又比如125的因数5个数为3。
其实更高级一点,我们换个想法。如果我们直接将n除以5,得到的就是n中所有能整除5的数的个数,为什么呢?把5理解为步长就好理解,5,10,15…,是不是呢?将n/5再除以5,得到的就是n中所有能整除25的数的个数;同样用步长理解,25,50,75…,是不是呢?直到n为0退出循环。这算法的时间复杂度就降低到了 l o g ( N / 5 ) log(N/5) log(N/5)。
class Solution {
public:
/*
* @param n: A long integer
* @return: An integer, denote the number of trailing zeros in n!
*/
long long trailingZeros(long long n) {
long long count = 0;
while (n)
{
n /= 5;
count += n;
}
return count;
}
};
Note
我的想法是将B中的元素逐个的插入A中。当B最后一个元素的值大于A中最后一个元素的值时,刚好可以在 i 到达A.size()前插入完;反之,可在下一个while中将剩余的B中的元素插入A的末尾。
class Solution {
public:
/**
* @param A: sorted integer array A
* @param B: sorted integer array B
* @return: A new sorted integer array
*/
vector<int> mergeSortedArray(vector<int> &A, vector<int> &B) {
vector<int> C;
int i = 0, j = 0;
while (i < A.size() && j < B.size())
{
if (B[j] < A[i])
A.insert(A.begin() + i, B[j++]);
else
++i;
}
while (j < B.size())
{
A.insert(A.begin() + i, B[j++]);
++i;
}
return A;
}
};
Note
题目的意思就是把字符串末尾的offset位字符移到开头,当然offset要先做处理,大于字符串长度时要减小。我的想法就是将前面的str.length() - offset位字符串给一个新的字符串,然后删除这一部分,再将新字符串连接到旧字符串末尾。
class Solution {
public:
/**
* @param str: An array of char
* @param offset: An integer
* @return: nothing
*/
void rotateString(string &str, int offset) {
if (str.length() == 0)
return;
string temp;
int end = str.length() - offset % str.length();
temp.insert(temp.begin(), str.begin(), str.begin() + end);
str.erase(str.begin(), str.begin() + end);
str += temp;
}
};
Note
两段代码都能达到13ms以上,网速够好的情况下。只有一点要记住,必须先判断能否同时被3和5整除。
class Solution {
public:
/**
* @param n: An integer
* @return: A list of strings.
*/
vector<string> fizzBuzz(int n) {
vector<string> vecstr;
for (int i = 1; i <= n; ++i)
{
int a = i % 10;
if (i % 3 == 0)
{
if (a == 0 || a == 5)
vecstr.push_back("fizz buzz");
else
vecstr.push_back("fizz");
}
else if (a == 0 || a == 5)
vecstr.push_back("buzz");
else
vecstr.push_back(to_string(i));
}
return vecstr;
}
};
class Solution {
public:
/**
* @param n: An integer
* @return: A list of strings.
*/
vector<string> fizzBuzz(int n) {
vector<string> vecstr;
for (int i = 1; i <= n; ++i)
{
if (i % 3 == 0 && i % 5 == 0)
vecstr.push_back("fizz buzz");
else if (i % 3 == 0)
vecstr.push_back("fizz");
else if (i % 5 == 0)
vecstr.push_back("buzz");
else
vecstr.push_back(to_string(i));
}
return vecstr;
}
};
Note
对二分查找进行了一点改进,因为这是一个存在重复元素的数组,所以一旦发现了同样的元素,就不再进行查找而是一直往左减小mid直到不再等于target。这点小小的改进竟然使我的耗时成了月榜第一。。。
class Solution {
public:
/**
* @param nums: The integer array.
* @param target: Target to find.
* @return: The first position of target. Position starts from 0.
*/
int binarySearch(vector<int> &nums, int target) {
int mid, left = 0, right = nums.size() - 1;
while (left <= right)
{
mid = (left + right) / 2;
if (nums[mid] == target)
{
while (nums[mid - 1] == target)
--mid;
return mid;
}
else if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1;
}
};
–
Note
两次二分查找,第一次二分是为了确定target可能在哪一行,第二次二分是为了确定target是否存在二维矩阵中。其中要注意,第一次二分后的right,就是它可能存在的行号。其他的,就注意vector
class Solution {
public:
/**
* @param matrix: matrix, a list of lists of integers
* @param target: An integer
* @return: a boolean, indicate whether matrix contains target
*/
bool searchMatrix(vector<vector<int>> &matrix, int target) {
int len = matrix.size();
if (target > matrix[len - 1][matrix[len - 1].size() - 1] || target < matrix[0][0])
return false;
int mid, left = 0, right = len - 1;
while (left <= right)
{
mid = (left + right) / 2;
if (matrix[mid][0] == target)
return true;
else if (matrix[mid][0] < target)
left = mid + 1;
else
right = mid - 1;
}
int t = right;
left = 0, right = matrix[t].size() - 1;
while (left <= right)
{
mid = (left + right) / 2;
if (matrix[t][mid] == target)
return true;
else if (matrix[t][mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
};
Note
正常写法如第一段代码所示,用指针p遍历原链表,然后利用头插法新建一个链表并返回头结点的下一个结点即可。看了讨论之后发现了一个更棒的方法,如果我们把链表反向指一下,能更快实现链表的翻转。即将 0->1->2->3->4->NULL 变为 NULL<-0<-1<-2<-3<-4。实现起来很简单,从头一个一个往左指(表现为指向自己的前一个结点)即可,但千万不要在往左指的过程中丢失了右边的链表。
注意此题没有头结点,头结点是不含任何信息的。
/**
* Definition of singly-linked-list:
*
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: n
* @return: The new head of reversed linked list.
*/
ListNode * reverse(ListNode * head) {
if (head == NULL)
return head;
ListNode *nhead = new ListNode;
nhead->val = 0;
nhead->next = NULL;
while (head != NULL)
{
ListNode *q = new ListNode;
q->val = head->val;
q->next = nhead->next;
nhead->next = q;
head = head->next;
}
return nhead->next;
}
};
/**
* Definition of singly-linked-list:
*
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: n
* @return: The new head of reversed linked list.
*/
ListNode * reverse(ListNode * head) {
if (head == NULL)
return head;
ListNode *nhead = NULL;
ListNode *curr = head;
ListNode *p;
while (curr != NULL)
{
p = curr->next;
curr->next = nhead;
nhead = curr;
curr = p;
}
return nhead;
}
};
一定要自己写一遍哦~~~