1 数组中重复的数据
给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。
找到所有出现两次的元素。
你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?
示例:
输入: [4,3,2,7,8,2,3,1] 输出: [2,3]
首先看一个简单的思路,即使用额外空间哈希表进行存储元素,时间复杂度O(n),空间复杂度O(n).
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
int len = nums.size();
int *a = (int*)calloc(len+1,sizeof(int));
vector<int> res;
for(int num:nums)
{
a[num]+=1; //将遍历的数作为数组下标进行统计
if(a[num]>=2) res.push_back(num);
}
free(a);
return res;
}
};
另外可以在原数组上根据下标进行交换操作,即假如里边的数是从0~n-1的,那么我们可以通过交换让这些数刚好对应上数组下标,本题中的数是从1开始的,所以就下标加1,即下标0放数字1,下标1放2,以此类推。这样我们得到一个数与它对应的下标减一的位置进行交换,如下:
7 3 2 4 8 2 3 1
3 3 2 4 8 2 7 1
2 3 3 4 8 2 7 1
3 2 3 4 8 2 7 1
3 2 3 4 1 2 7 8
1 2 3 4 3 2 7 8
交换完成后我们可以看到已经满足我们上边述说的下标0放1,下标1放2,,,这样遍历一遍,与下标不一致的就是重复的。时间复杂度O(n),空间复杂度O(1)。
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
int len = nums.size();
vector<int> res;
int tmp;
for(int i=0;i<len;++i)
{
while(nums[i]!=nums[nums[i]-1])//这个while实际执行次数很小,所以时间复杂度按外层计算
{
tmp=nums[i];
nums[i]=nums[tmp-1];
nums[tmp-1]=tmp;
}
}
for(int i=0;i<len;++i)
{
if(nums[i]!=i+1)
res.push_back(nums[i]);
}
return res;
}
};
2 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(!l1) return l2;
if(!l2) return l1;//判断是否为空
ListNode *s,*head;
if(l1->val<=l2->val)//先将小的链表头拿出来作为要合并的头
{
s=l1;
l1=l1->next;
s->next=NULL;
}
else
{
s=l2;
l2=l2->next;
s->next=NULL;
}
head=s;
while(l1&&l2)//遍历链表,谁小接谁
{
if(l1->val<=l2->val)
{
s->next=l1;
l1=l1->next;
}
else
{
s->next=l2;
l2=l2->next;
}
s=s->next;
s->next=NULL;
}
if(!l1)//遍历完将剩下的另一个接后面
s->next=l2;
if(!l2)
s->next=l1;
return head;
}
};
3 路径总和 II
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1
返回:
[ [5,4,11,2], [5,8,4,5] ]
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<int> path;//用于保存搜索路径,遍历与回溯
findPath(root,path,sum,0);
return res;
}
void findPath(TreeNode*root,vector<int> path,int sum,int cursum)
{
if(root==NULL) return;
cursum+=root->val;//将当前节点的值累加并加入路径
path.push_back(root->val);
bool isleaf=root->left==NULL&&root->right==NULL;
if(cursum==sum&&isleaf)//累加值等于要求的值,并且是叶子节点,则保存当前路径
res.push_back(path);
//先序遍历
if(root->left!=NULL)
findPath(root->left,path,sum,cursum);
if(root->right!=NULL)
findPath(root->right,path,sum,cursum);
path.pop_back();//回溯到上一层
}
};