一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
剑指 Offer 20. 表示数值的字符串
思路 (模拟,字符串处理) O(n)
遍历整个字符串,将所有的不合法情况都去除掉,剩下的就是合法情况。
具体过程如下:
1、首先去除行首和行尾空格,如果去除完之后,整个字符串为空,则返回false。
2、行首如果有一个正负号,直接忽略。
3、如果字符串为空或只有一个'.',则不是一个合法方案。 4、遍历整个字符串s,对于当前字符s[i]:
-
s[i]为数字,则不做任何处理。 -
s[i] == '.',.的个数加1。如果此时'.'在'e'后面出现或者'.'的个数多于1个,则返回false。【1e2.1,1e2.1.1】 -
s[i] == 'e' || s[i] == 'E',e的个数加1。- 如果此时
'e'的后面为空或者'e'多于1个或者'e'的前面为空或者为'.e',则返回false。【12e,12e3e,e12,12.e3,.e】 'e'后面紧跟着正负号,但正负号后面为空,则返回false。【1e2+】
- 如果此时
-
s[i]为其他字符,返回false。
5、排除了各种非法情况,此时s则为合法方案,我们返回true。
c++代码
class Solution {
public:
bool isNumber(string s) {
int i = 0;
while (i < s.size() && s[i] == ' ') i ++ ; //删除行首空格
int j = s.size() - 1;
while (j >= 0 && s[j] == ' ') j -- ; //删除行末空格
if (i > j) return false;
s = s.substr(i, j - i + 1);
if (s[0] == '-' || s[0] == '+') s = s.substr(1); //忽略行首正负号
if (s.empty() || s[0] == '.'&& s.size() == 1) return false;//如果字符串为空或只有一个'.',则不是一个合法方案
int dot = 0, e = 0;
for (int i = 0; i < s.size(); i ++ )
{
if (s[i] >= '0' && s[i] <= '9');//遇到数字不做任何处理
else if (s[i] == '.')
{
dot ++ ; //'.'的个数加1
if (e || dot > 1) return false;//'.'在'e'后面出现 , '.'的个数多于1个;
}
else if (s[i] == 'e' || s[i] == 'E')
{
e ++ ; //'e'的个数加1
//'e'的后面为空或者'e'多于1个或者'e'的前面为空或者为
if (i + 1 == s.size() || !i || e > 1 || i == 1 && s[0] == '.') return false;
if (s[i + 1] == '+' || s[i + 1] == '-')//'e'后面紧跟着正负号,但正负号后面为空
{
if (i + 2 == s.size()) return false;
i ++ ; //跳过正负号
}
}
else return false; //其他字符
}
return true;
}
};
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
思路
(双指针扫描) O(n)
用两个指针分别从首尾开始,往中间扫描。扫描时保证第一个指针前面的数都是奇数,第二个指针后面的数都是偶数。
每次迭代时需要进行的操作:
- 第一个指针一直往后走,直到遇到第一个偶数为止;
- 第二个指针一直往前走,直到遇到第一个奇数为止;
- 交换两个指针指向的位置上的数,再进入下一层迭代,直到两个指针相遇为止;
时间复杂度分析: 当两个指针相遇时,走过的总路程长度是 n,所以时间复杂度是 O(n)。
c++代码
class Solution {
public:
vector<int> exchange(vector<int>& nums) {
int i = 0, j = nums.size() - 1;
while(i < j){
while(i < j && nums[i] % 2 == 1) i++;
while(i < j && nums[j] % 2 == 0) j--;
swap(nums[i], nums[j]);
}
return nums;
}
};
剑指 Offer 22. 链表中倒数第k个节点
思路
(链表) O(n)
由于单链表不能索引到前驱节点,所以只能从前往后遍历。
我们一共遍历两次:
-
第一次遍历得到链表总长度 n;
-
链表的倒数第 k 个节点,相当于正数第n−k+1 个节点。所以第二次遍历到第 n−k+1 个节点,就是我们要找的答案。
注意:
当 k>n 时要返回nullptr。
时间复杂度分析: 链表总共遍历两次,所以时间复杂度是 O(n)。
c++代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
int n = 0;
for(auto p = head; p ; p = p->next) n++;
if(k > n) return NULL;
auto p = head;
for(int i = 0; i < n - k; i++) p = p->next;
return p;
}
};