231. 2 的幂
这道题就没什么难度,我重拳出击!
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n==0)
return false;
while(n)
{
if(n==1)
return true;
if(n%2!=0&&n!=1)
return false;
n=n/2;
}
return true;
}
};
但是很慢
让我们看看官方题解怎么写
解法1
class Solution {
private:
static constexpr int BIG = 1 << 30;
public:
bool isPowerOfTwo(int n) {
return n > 0 && BIG % n == 0;
}
};
在题目给定的 32 位有符号整数的范围内,最大的 2 的幂为 230=1073741824。我们只需要判断 n 是否是 230 的约数即可
哇,好天才的想法
正经的解法也很快
解法2
class Solution {
public:
bool isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
};
一个数 n 是 2 的幂,当且仅当 n 是正整数,并且 n 的二进制表示中仅包含 1 个 1。
因此我们可以考虑使用位运算,将 n 的二进制表示中最低位的那个 1 提取出来,再判断剩余的数值是否为 0 即可
n & (n - 1)可以直接将 n 二进制表示的最低位 1 移除
解法3
class Solution {
public:
bool isPowerOfTwo(int n) {
return n > 0 && (n & -n) == n;
}
};
n & (-n)可以直接获取 n 二进制表示的最低位的 1
232. 用栈实现队列
感觉和用队列实现栈的原理差不多
简单写写
class MyQueue {
public:
stack<int>st1;
stack<int>st2;
MyQueue() {
}
void push(int x) {
st1.push(x);
}
int pop() {
int size=st1.size();
while(--size)
{
int num=st1.top();
st1.pop();
st2.push(num);
}
int result=st1.top();
st1.pop();
size=st2.size();
while(size--)
{
int num=st2.top();
st2.pop();
st1.push(num);
}
return result;
}
int peek() {
int size=st1.size();
while(--size)
{
int num=st1.top();
st1.pop();
st2.push(num);
}
int result=st1.top();
size=st2.size();
while(size--)
{
int num=st2.top();
st2.pop();
st1.push(num);
}
return result;
}
bool empty() {
return st1.empty();
}
};
不过代码比较冗余,其实可以这么写:
class MyQueue {
public:
stack<int> stIn;
stack<int> stOut;
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
stIn.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
// 只有当stOut为空的时候,再从stIn里导入数据(导入stIn全部数据)
if (stOut.empty()) {
// 从stIn导入数据直到stIn为空
while(!stIn.empty()) {
stOut.push(stIn.top());
stIn.pop();
}
}
int result = stOut.top();
stOut.pop();
return result;
}
/** Get the front element. */
int peek() {
int res = this->pop(); // 直接使用已有的pop函数
stOut.push(res); // 因为pop函数弹出了元素res,所以再添加回去
return res;
}
/** Returns whether the queue is empty. */
bool empty() {
return stIn.empty() && stOut.empty();
}
};
大佬表示:
peek()的实现,直接复用了pop()。
在工业级别代码开发中,最忌讳的就是 实现一个类似的函数,直接把代码粘过来改一改就完事了。
这样的项目代码会越来越乱,一定要懂得复用,功能相近的函数要抽象出来,不要大量的复制粘贴,很容易出问题!
234. 回文链表
不知道该怎么做
大佬的思路为
先找到中间结点,然后反转中间结点后面到结尾的所有结点。最后一一判断头结点开始的结点和中间结点往后开始的结点是否相等。如果一直相等,就是回文链表,如果有不相等的,直接返回不是回文链表
其中,中间节点使用快慢指针寻找:
慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。通过慢指针将链表分为两部分。
写了很久。。。而且很慢。。。在反转链表上错误比较多
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head==nullptr||head->next==nullptr)
return true;
ListNode* slow,*fast;
slow=head;
fast=head;
int n=1;
while(fast->next!=nullptr&&fast->next->next!=nullptr)
{
slow=slow->next;
fast=fast->next->next;
n++;
}
ListNode* cur=slow->next;
ListNode* temp;
ListNode* pre=nullptr;
slow->next=nullptr;
while(cur)
{
temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
while(head&&pre)
{
if(head->val!=pre->val)
return false;
if(n){
head=head->next;
pre=pre->next;
}
}
return true;
}
};
不过在并发环境下,该方法也有缺点。在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。