初级算法
字符串转换整数(atoi)
请你来实现一个 atoi
函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
示例 2:
1 2 3 4
| 输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
|
示例 3:
1 2 3
| 输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
|
示例 4:
1 2 3 4
| 输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
|
示例 5:
1 2 3 4
| 输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
|
比较重要的操作是对字符串进行处理,获得想要的只含有数字和正负号的字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class Solution { public: int myAtoi(string str) { long res = 0; int i = 0; int flag = 1; vector<char> resc; while(str[i] == ' ') { ++i; } if(str[i] == '-') { flag = -1; ++i; } else if(str[i] == '+') { ++i; } else if(str[i] >= '0' && str[i] <= '9') {} else { return 0; } for(;i < str.size(); ++i) { if(str[i] >= '0' && str[i] <= '9') resc.push_back(str[i]); else break; } for(i = 0; i < resc.size(); ++i) { res = res * 10 + (resc[i] - '0'); if(res > INT_MAX && flag == 1) return INT_MAX; if(flag == -1 && flag * res <= INT_MIN) return INT_MIN; } return flag * res; } };
|
实现strStr()
先挖个坑,是用kmp实现的,想详细看一下然后写kmp的详细内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| class Solution { public: void getNext(vector<int> &next,const string needle) { int lp=next.size(); int k=-1; int j=0; next[0]=-1; while(j<lp-1) { if(k==-1||needle[j]==needle[k]) { if(needle[++j]==needle[++k]) { next[j]=next[k]; } else { next[j]=k; } } else { k=next[k]; } } } int strStr(string haystack, string needle) { int ls=haystack.length(); int lp=needle.length(); if(lp==0) return 0; int i=0; int j=0; vector<int> next(lp,0); getNext(next,needle); while(i<ls && j<lp) { if(j==-1 || haystack[i]==needle[j]) { i++; j++; } else { j=next[j]; } } if(j>=lp) return i-lp; else return -1; } };
|
报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1 2 3 4 5
| 1. 1 2. 11 3. 21 4. 1211 5. 111221
|
1
被读作 "one 1"
("一个一"
) , 即 11
。
11
被读作 "two 1s"
("两个一"
), 即 21
。
21
被读作 "one 2"
, “one 1"
("一个二"
, "一个一"
) , 即 1211
。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
示例 2:
主要就是找规律然后按照规律报下去直到达到要求的数字就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { public: string countAndSay(int n) { string res = "", temp = "1"; if (n == 1) { return temp; } temp = "11"; if(n == 2) return temp; char pre = temp[0]; int cnt = 1; for (int i = 2; i < n; ++i) { for (int j = 1; j < temp.size(); ++j) { if (pre == temp[j]) { ++cnt; } else { res.push_back(char('0' + cnt)); res.push_back(pre); cnt = 1; } pre = temp[j]; } res.push_back(char('0' + cnt)); res.push_back(pre); if (i < n - 1) { temp.clear(); temp = res; pre = temp[0]; cnt = 1; res.clear(); } } return res; } };
|
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
1 2
| 输入: ["flower","flow","flight"] 输出: "fl"
|
示例 2:
1 2 3
| 输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。
|
说明:
所有输入只包含小写字母 a-z
。
我的想法是先求第一个和第二个的最长公共前缀,再拿着这个前缀和后面的求,迭代下去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { public: void Prefix2(string str1, string str2, string& res) { for(int i = 0; i < min(str1.size(), str2.size()); ++i) { if(str1[i] == str2[i]) { res.push_back(str1[i]); } else { break; } } } string longestCommonPrefix(vector<string>& strs) { string res = ""; if(strs.size() == 0||strs[0] == "") return res; if(strs.size() == 1) return strs[0]; Prefix2(strs[0], strs[1], res); if(res == "") return res; for(int i = 2; i < strs.size(); ++i) { string tmp = res; res = ""; Prefix2(tmp, strs[i], res); if(res == "") return res; } return res; } };
|
删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 – head = [4,5,1,9],它可以表示为:
示例 1:
1 2 3
| 输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
|
示例 2:
1 2 3
| 输入: head = [4,5,1,9], node = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
|
说明:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
给出的参数是要删除节点的指针,所以考虑如何删除这一节点。
方法是将下一节点的值覆盖到本节点的值上,并改变本节点的next指向下一个节点的next,最后释放本节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
class Solution { public: void deleteNode(ListNode* node) { ListNode *p = node->next; node->val = p->val; node->next = p->next; delete p; } };
|
删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
1 2 3
| 给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
|
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
一趟扫描是用双指针,一个指针先走n步,然后后一个指针再和先走的一块走,当先走的指针到达链表尾部时,后走的就到达倒数第n个节点,然后将其删除就ok。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { int i = 0, flag = 0; ListNode* cur = head; ListNode* res = head; ListNode* pre; while(i < n - 1) { cur = cur->next; ++i; } while(cur->next != NULL) { pre = res; res = res->next; cur = cur->next; } if(res == head && res->next == NULL) { delete res; return NULL; } else if(res == head) { res = res->next; delete head; return res; } else { pre->next = res->next; delete res; } return head; } };
|
反转链表
反转一个单链表。
示例:
1 2
| 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
|
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
首先迭代,从第二个节点开始,逐个摘下来,并用头插法将其插到第一个节点前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
class Solution { public: ListNode* reverseList(ListNode* head) { if(head == NULL) return NULL; if(head->next == NULL) return head; ListNode* pre = head->next; ListNode* cur = pre->next; head->next = NULL; while(cur!= NULL) { pre->next = head; head = pre; pre = cur; cur = cur->next; } pre->next = head; head = pre; return head; } };
|
递归实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
class Solution { public: ListNode* reverseList(ListNode* head) { if(head == NULL || head->next ==NULL) return head; ListNode* newhead = reverseList(head->next); head->next->next = head; head->next = nullptr; return newhead; } };
|
合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
1 2
| 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
|
如果l1值小于l2值时,l1往后走一个,l1的后续节点是mergeTwoLists(l1->next, l2);
l2值小于l1值时同理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(l1==NULL) return l2; if(l2==NULL) return l1; if(l1->val < l2->val){ l1->next=mergeTwoLists(l1->next,l2); return l1; } else{ l2->next=mergeTwoLists(l1,l2->next); return l2; }
} };
|
回文链表
请判断一个链表是否为回文链表。
示例 1:
示例 2:
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
用了最容易弄懂的解法,将后半跳链元素值入栈,最后一个一个比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
class Solution { public: bool isPalindrome(ListNode* head) { if(head == NULL || head->next == NULL) return true; ListNode* fast = head; ListNode* slow = head; while(fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; } stack<int> is; while(slow != NULL) { is.push(slow->val); slow = slow->next; } while(!is.empty()) { if(is.top() == head->val) { is.pop(); head = head->next; } else { break; } } if(is.empty()) return true; else return false; } };
|
环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
示例 1:
1 2 3
| 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
|
示例 2:
1 2 3
| 输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
|
示例 3:
1 2 3
| 输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
|
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
两个指针,一个一次走两步,一个一次走一步,能碰到就是有环,走到空就是无环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
class Solution { public: bool hasCycle(ListNode *head) { if(head == NULL || head->next == NULL) return false; ListNode *fast = head; ListNode *slow = head; while(fast->next && slow && fast->next->next) { fast = fast->next->next; slow = slow->next; if(fast == slow) return true; } return false; } };
|