LeetCode数据结构与算法学习Day02
题目引用自
https://leetcode-cn.com/
图解数据结构与算法
每日学习Day02学习笔记
20 数值表示字符串
题目描述:
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
1、若干空格
2、一个小数或者整数
3、(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个整数
4、若干空格
小数(按顺序)可以分成以下几个部分:
1、(可选)一个符号字符(’+’ 或 ‘-’)
2、下述格式之一:
至少一位数字,后面跟着一个点 ‘.’
至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
一个点 ‘.’ ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
1、(可选)一个符号字符(’+’ 或 ‘-’)
2、至少一位数字
部分数值列举如下:
["+100", “5e2”, “-123”, “3.1416”, “-1E-16”, “0123”]
部分非数值列举如下:
[“12e”, “1a3.14”, “1.2.3”, “±5”, “12e+5.4”]
解题思路:
1、直接使用正则表达式匹配字符串
2、利用状态机、状态转移来实现字符串匹配。
----先根据题目描述求出各种状态与状态对应的转移状态有什么,然后依次对字符串每一位进行判断。
----接触状态机较少,用的时间比较多。
class Solution {
public:
enum stats{
STATE_STARTBLANK,
STATE_SIGN,
STATE_INT,
STATE_INTPOINT,
STATE_NOINTPOINT,
STATE_DBL,
STATE_E,
STATE_ESIGN,
STATE_EDBL,
STATE_ENDBLANK
};
enum type{
NUMBER,
E,
POINT,
SIGN,
BLANK,
OTHER
};
type istype(char ch){
if(ch >='0' && ch <= '9')
return NUMBER;
else if(ch == 'e' || ch == 'E')
return E;
else if(ch == '.')
return POINT;
else if(ch == '+' || ch == '-')
return SIGN;
else if(ch == ' ')
return BLANK;
else
return OTHER;
};
bool isNumber(string s) {
unordered_map<stats,unordered_map<type,stats>>dp{
{
STATE_STARTBLANK,{
{BLANK,STATE_STARTBLANK},{NUMBER,STATE_INT},
{POINT,STATE_NOINTPOINT},{SIGN,STATE_SIGN},
}
},
{
STATE_SIGN,{
{NUMBER,STATE_INT},{POINT,STATE_NOINTPOINT},
}
},
{
STATE_INT,{
{NUMBER,STATE_INT},{E,STATE_E},
{POINT,STATE_INTPOINT},{BLANK,STATE_ENDBLANK},
}
},
{
STATE_INTPOINT,{
{NUMBER,STATE_DBL},{E,STATE_E},
{BLANK,STATE_ENDBLANK},
}
},
{
STATE_NOINTPOINT,{
{NUMBER,STATE_DBL},
}
},
{
STATE_DBL,{
{NUMBER,STATE_DBL},{E,STATE_E},
{BLANK,STATE_ENDBLANK},
}
},
{
STATE_E,{
{NUMBER,STATE_EDBL},{SIGN,STATE_ESIGN},
}
},
{
STATE_ESIGN,{
{NUMBER,STATE_EDBL},
}
},
{
STATE_EDBL,{
{NUMBER,STATE_EDBL},{BLANK,STATE_ENDBLANK},
}
},
{
STATE_ENDBLANK,{
{BLANK,STATE_ENDBLANK},
}
}
};
int length = s.length();
stats ss = STATE_STARTBLANK;
for(int i = 0;i<length;++i){
type tp = istype(s[i]);
if(dp[ss].find(tp) == dp[ss].end())
return false;
else
ss = dp[ss][tp];
}
return ss == STATE_INT|| ss == STATE_INTPOINT || ss == STATE_DBL || ss == STATE_ENDBLANK || ss == STATE_EDBL;
}
};
执行用时:
76 ms, 在所有 C++ 提交中击败了5.47%的用户
内存消耗:
15.2 MB, 在所有 C++ 提交中击败了19.24%的用户
24 反转链表
题目描述:
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
解题思路:
1、递归反转
2、双向指针反转
class Solution {
public:
ListNode* isReverse(ListNode* pre,ListNode* now){
if(now==nullptr)
return pre;
ListNode* result = isReverse(now,now->next);
now->next = pre;
return result;
}
ListNode* reverseList(ListNode* head) {
return isReverse(nullptr,head);
}
};
执行用时:
4 ms, 在所有 C++ 提交中击败了95.65%的用户
内存消耗:
8.3 MB, 在所有 C++ 提交中击败了5.02%的用户
30 包含min函数的栈
题目描述:
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
解题思路:
由于要求时间复杂度为O(1),则无法使用遍历。
使用双栈,一个栈正常保存弹入元素,另一个栈保存最小值。在弹入栈的时候作判断,弹入元素是否小于最小栈顶元素,是的话弹入最小栈,否则将最小栈的栈顶元素再次弹入,同时弹出栈顶元素时,两个栈同时弹出一个栈顶元素。
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
st.push(x);
if(st_min.empty()||x < st_min.top())
st_min.push(x);
else
st_min.push(st_min.top());
}
void pop() {
st.pop();
st_min.pop();
}
int top() {
return st.top();
}
int min() {
return st_min.top();
}
stack<int>st;
stack<int>st_min;
};
执行用时:
28 ms, 在所有 C++ 提交中击败了39.70%的用户
内存消耗:
14.6 MB, 在所有 C++ 提交中击败了90.27%的用户
35 复杂链表的复制
题目描述:
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
解题思路:
1、map两次遍历映射。第一次遍历链表映射各个节点,第二次遍历映射各个节点的next与random节点关系。
2、新增节点并修改。
//1、map实现
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr)
return head;
unordered_map<Node*,Node*>dp;
Node* cur = head;
while(cur!=nullptr)
{
dp[cur] = new Node(cur->val);
cur = cur->next;
}
cur = head;
while(cur!=nullptr)
{
dp[cur]->next = dp[cur->next];
dp[cur]->random = dp[cur->random];
cur = cur->next;
}
return dp[head];
}
};
执行用时:
12 ms, 在所有 C++ 提交中击败了60.76%的用户
内存消耗:
10.9 MB, 在所有 C++ 提交中击败了83.52%的用户
拼接实现的时候比较麻烦,需要注意各个指针的指向。
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr)
return head;
Node* cur = head;
while(cur!=nullptr)
{
Node* nd = new Node(cur->val);
nd->next = cur->next;
cur->next = nd;
cur = nd->next;
}
cur = head;
while(cur!=nullptr)
{
if(cur->random != nullptr)
cur->next->random = cur->random->next;
cur = cur->next->next;
}
cur = head->next;
Node* pre = head, *res = head->next;
while(cur->next != nullptr) {
pre->next = pre->next->next;
cur->next = cur->next->next;
pre = pre->next;
cur = cur->next;
}
pre->next = nullptr;
return res;
}
};
执行用时:
8 ms, 在所有 C++ 提交中击败了89.52%的用户
内存消耗:
10.9 MB, 在所有 C++ 提交中击败了95.95%的用户