文章目录
给定需求:
一个数组内含有一些负数 一些0 和一些正数 ,这些数字按升序排列,要求找出其中的第一个正数和最最后一个负数
注意到一点:
因为数组是排好序的,因此第一个正数的左边是0 和 最后一个负数的右边是0
//找有序数组第一个正数和最后一个负数3
//因为数组是有序的 因此最后一个负数的右边是0 第一个正数的左边也是0
class Solution
{
public:
vector<int>findNum(vector<int>& nums)
{
int plusCount = 0;//正数的个数
int minusCount = 0;//负数的个数
int zeroCount = 0;//0的个数
vector<int>res;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] > 0)plusCount++;
else if (nums[i] < 0)minusCount++;
else zeroCount++;
}
res.push_back(nums[minusCount - 1]);
res.push_back(nums[minusCount + zeroCount]);
return res;
}
return res;
};
int main()
{
vector<int>nums = { -1,-2,-6,0,0,0,5,8,7,6,3 };
vector<int>ans;
Solution so;
ans = so.findNum(nums);
cout << ans[0] << endl;
cout<<ans[1] << endl;
system("pause");
return 0;
}
//找出第一个正数和最后一个负数
class Solution
{
public:
vector<int>findNumbers(vector<int>&nums)
{
vector<int>vec;
int left = 0, right = nums.size() - 1;
while (left < right)
{
if (nums[left] == 0)vec.push_back(nums[left--]);//从左向右遍历 当遇到第一个为0的数字时,这个数左侧的数字就是最后一个负数;
else left++;
if (nums[right] == 0)vec.push_back(nums[right++]);//从右向左遍历 当遇到第一个为0的数字时,这个数字右侧的数字就是第一个正数;
else right--;
}
return vec;
}
};
Leetcode 24 两两交换链表中的节点
题目背景:
示例:
输入:1->2->3->4
输出:2->1->4->3
实现代码:
struct ListNode
{
int val;
ListNode* next;
ListNode(int x) :val(x), next(NULL) {};
};
class Solution
{
public:
ListNode* swapPairs(ListNode* head)
{
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* temp = dummyHead;
while (temp->next != NULL && temp->next->next != NULL)
{
ListNode* p1 = temp->next;//p1指向第一个节点
ListNode* p2 = temp->next->next;//p2指向第二个节点
temp->next = p2;//p2指向第一个节点
p1->next = p2->next;//实现前两个节点的位置交换
p2->next = p1;//p1位于p2的下一个节点
temp = p1;//更新temp 继续向下遍历
}
return dummyHead->next;
}
};
Leetcode 206 简单 双指针实现链表反转
//双指针实现反转链表
class Solution
{
public:
ListNode* reverseList(ListNode* head)
{
ListNode* cur = head, * pre = nullptr;
while (cur != nullptr)
{
ListNode* temp = cur->next; //把cur->next节点用temp指针保存一下
cur->next = pre;//改变cur->next指针的指向 将cur->next指向pre,这里进行了第一次反转
//更新pre 和cur指针 继续反转下一个
pre = cur;//让pre指针指向pre指针的位置
cur = temp;//让cur指针指向temp指针的位置
}
return pre;//pre最后指向原链表的最后一个节点 就是新链表的第一个节点
}
};
【重点理解】
这里我们需要三个指针:pre cur temp
cur指针用来指向当前节点
;
pre指针用来指向当前节点的前一个节点
;
temp用来记住当前节点的后一个节点,因为cur指针指向前一个节点后就断开了和后一个节点的联系,如果此时没有一个指针记住后一个节点的话就无法继续向下遍历进行下一组的反转了
;
这是首先反转头节点cur
和空节点pre
,再反转第一个节点和第二个节点,1<–2,原先是1–>2
让pre和cur指针继续向后移动,反转2和3;变成2<–3 之前是 2–>3
Leetcode 92 反转链表(二)
题目背景:
算法思路:
整体思想是,在待反转区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置;
具体实现:使用三个指针变量pre,cur,next
来记录反转的过程中需要的变量,它们的意义如下:
cur:指向待反转区域的第一个节点left
;
next:永远指向cur指针的下一个节点,循环过程中,cur变化后next会变化
;
pre:永远指向待反转区域的第一个节点left的前一个节点
,在循环过程中不变;
在这个思路下;我们进行实现上述五步:
第一步:我们使用 ①、②、③ 标注「穿针引线」的步骤。
操作步骤:
先将 curr 的下一个节点记录为 next;
执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点; `cur->next=next->next;`
执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点;`next->next=pre->next;`
执行操作 ③:把 pre 的下一个节点指向 next。`pre->next=next;`
第 1 步完成以后「拉直
」的效果如下:
第 2 步,同理。同样需要注意 「穿针引线
」操作的先后顺序。
第 2 步完成以后「拉直」的效果如下:
第 3 步,同理。
第 3 步完成以后「拉直」的效果如下:
//反转区间[left,right]之间的节点
class Solution
{
public:
ListNode* reverseBetween(ListNode* head, int left, int right)
{
ListNode* dummyHead = new ListNode(0);//初始化一个伪头节点
dummyHead->next = head;
ListNode* pre = dummyHead;//先初始化指针pre指向伪头节点
for (int i = 0; i < left - 1; i++)
{
pre = pre->next;//通过遍历 将pre指针移动到指向待反转区域的第一个节点的前一个节点
}
ListNode* cur = pre->next;//cur指针指向待反转区域的第一个节点
for (int i = 0; i < right - left; i++)
{
//这里实现的是将待反转区域的第二个节点插入到第一个节点之前,不断的实现,最终实现反转
ListNode*next = cur->next;//cur的下一个节点记录为next
cur->next = next->next;//把cur的下一个节点指向next的下一个节点
next->next = pre->next;//把next的下一个节点指向pre的下一个节点
pre->next= next;//把pre的下一个节点指向next
}
return dummyHead->next;
}
};
剑指offer 06 从尾到头打印链表 简单题目 【字节后台】
//倒序输出链表(从尾到头打印链表) 简单题
class Solution
{
public:
vector<int>reversePrint(ListNode* head)
{
stack<int>s;//栈
vector<int>res;//容器
ListNode* pre = head;//定义一个头节点
while (pre)
{
s.push(pre->val);
pre = pre->next;
}
while (!s.empty())
{
res.push_back(s.top());//将栈顶元素依次入栈 实现倒序
s.pop();//删除栈顶元素
}
return res;//返回实现到序的栈
}
};
剑指offer 25 合并两个排序的链表 简单题目
//合并两个排序的链表
class Solution
{
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
ListNode* head = new ListNode(0);//初始化一个新的链表头节点,作为合并之后链表的头节点;
ListNode* ret = head;//初始化一个指针指向头节点用来将遍历到的节点连接起来;
while (l1 != NULL && l2 != NULL)
{
if (l1->val < l2->val)
{
ret->next = l1;//l1作为头节点
l1 = l1->next;//将l1更新为下一个节点
}
else
{
ret->next = l2;
l2 = l2->next;
} //上述判断完成后 ret指向的是倒数第二个节点的位置
ret = ret->next;//将ret指针指向最后一个节点的位置;
}
if (l1)ret->next = l1;//这里的操作是将两个链表剩下的部分链接到头节点后面;
else ret->next = l2;
return head->next;
}
};
leetcode 206 二叉树的最近公共祖先
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x),left(NULL),right(NULL){}
};
class Solution
{
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)// p q是进行比较的两个树节点
{
if (root == nullptr)return nullptr;
if (root == p || root == q)return root;//当输入的根节点恰好是进行比较的那两个节点 直接返回根节点即可
TreeNode* left = lowestCommonAncestor(root->left, p, q);//递归左子树 返回的left 和right是p,q中的一个;
TreeNode* right = lowestCommonAncestor(root->right, p, q);//递归右子树
if (left != nullptr && right != nullptr)return root;//left right 均不为空 说明进行比较的p q分别位与左右子树,那么其最近的公共祖先就是一开始输入的 root
if (left == nullptr && right == nullptr)return nullptr;//指定的p q不存在
return left == nullptr ? right : left;//有一个为空 那么最近的公共祖先就是另一个节点;p q在同一侧的情况
}
};