数据结构和算法
1、给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
数组的长度为 [1, 20,000]。
数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
给定整数数组 A 和 常数 m, 输出 A 中满足数列和为 m 的连续子序列个数 示例 输入: A = [1,2,3], m=3 输出: 2
思路:
1)累计求和,双层遍历求差是否为目标值,得到满足条件的个数
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n=nums.size();
vector<int> sum(n+1,0);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+nums[i-1];
int count=0;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
if(sum[j+1]-sum[i]==k) count+=1;
}
}
return count;
}
};
2)哈希表思路,累计求和放在哈希表中,然后看求和的数和目标值的差是否在哈希表中存在,以及存在的个数,以此求和得到满足条件的个数,初始化hash[0]=1
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash;
int sum = 0, ans = 0;
hash[0] = 1;
for(int num : nums) {
sum += num;
ans += hash[sum - k];
hash[sum]++;
}
return ans;
}
};
2、反转链表
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
// 递归方式
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//结束条件
if(head == NULL || head->next == NULL) return head;
//递归反转剩下的元素
ListNode* rev = reverseList(head->next);
//头节点变为最后一个节点
head->next->next = head;
//头节点指针设置为空
head->next = NULL;
return rev;
}
};
2)非递归方式
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL || head->next == NULL){
return head;
}
//前面一个节点
ListNode* pre = nullptr;
//当前节点
ListNode* cur = head;
while(cur != nullptr)
{
//指针先向后遍历
ListNode* tmp = cur->next;
//改变指针指向
cur->next = pre;
//前面一个节点变为当前节点、当前节点变为后面的节点
pre = cur;
cur = tmp;
}
return pre;
}
};
3、给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* merge(ListNode* l1, ListNode* l2){ //合并L1,L2两个有序链表
if(!l1) return l2;
if(!l2) return l1;
if(l1->val < l2->val){
l1->next = merge(l1->next, l2);
return l1;
}else{
l2->next = merge(l1, l2->next);
return l2;
}
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
int interval = 1;
int len = lists.size();
if(len==1){
return lists[0];
}
if(len==0){
return nullptr;
}
while(interval<len){
for(int i=0;i<len-interval;){
lists[i]=merge(lists[i],lists[i+interval]);
i=i+2*interval;
}
interval = interval*2;
}
return lists[0];
}
};
4、给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:
输入:s = ""
输出:0
两种思路:
1)用栈实现
class Solution {
public:
int longestValidParentheses(string s) {
int maxLen = 0;
stack<int> st;
st.push(-1);
for (int i = 0; i < s.size(); i++) {
char c = s[i];
if (c == '(') {
// 左括号的索引,入栈
st.push(i);
}
else {
// 遍历到右括号, 栈顶的左括号被匹配,出栈
st.pop();
if (st.size()!=0) {
// 栈未空,计算有效连续长度
int curMaxLen = i - st.top();
// 挑战最大值
maxLen = max(maxLen, curMaxLen);
}
else {
// 栈空了,入栈充当参照
st.push(i);
}
}
}
return maxLen;
}
};
2)动态规划思路:求最值问题
5、我们把数组 A 中符合下列属性的任意连续子数组 B 称为 “山脉”:
B.length >= 3
存在 0 < i < B.length - 1 使得 B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]
(注意:B 可以是 A 的任意子数组,包括整个数组 A。)
给出一个整数数组 A,返回最长 “山脉” 的长度。
如果不含有 “山脉” 则返回 0。
示例 1:
输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。
示例 2:
输入:[2,2,2]
输出:0
解释:不含 “山脉”。
class Solution {
public:
int longestMountain(vector<int>& arr) {
int len = arr.size();
vector<int> dp(len,0);
for(int i=1;i<len;i++){
if(arr[i]>arr[i-1]&&dp[i-1]==0){
dp[i]=max(dp[i-1]+2,0);
}else if(arr[i]>arr[i-1]){
dp[i]=max(dp[i-1]+1,0);
}
}
vector<int> dp2(len,0);
for(int i=len-1;i>0;i--){
if(arr[i]<arr[i-1]&&dp2[i]==0){
dp2[i-1]=max(dp2[i]+2,dp2[i]);
}else if(arr[i]<arr[i-1]){
dp2[i-1]=max(dp2[i]+1,dp2[i]);
}
}
int res = 0;
if(dp[len-1]==len||dp2[0]==len){
return 0;
}
for(int i=0;i<len;i++){
if(dp[i]>=2&&dp2[i]>=2 && (dp[i]+dp2[i]>res)){
res = dp[i]+dp2[i]-1;
}
}
return res;
}
};
6、单词搜索(leetcode 212,79)
给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
思路:回溯算法
class Solution {
public:
int h;
int w;
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
vector<string> res;
h = board.size();
w = board[0].size();
for(int k=0;k<words.size();k++){
for(int i = 0; i < h; i++){
for(int j = 0; j < w; ++j){
//尝试从每一个字母开始回溯
if(searchexist(board, words[k], 0, i, j)){
res.push_back(words[k]);
i = h;
j = w;
}
}
}
}
return res;
}
int searchexist(vector<vector<char>>& board, string &word, int n, int x, int y){
if(x < 0 || x > h-1 || y < 0 || y > w-1 || word[n] != board[x][y])
return 0;
//达成要求返回1
if(n == word.length()-1)
return 1;
//将用过的保存起来
char temp = board[x][y];
board[x][y] = 0;
//四个方回溯
int flag = searchexist(board, word, n+1, x+1, y)
||searchexist(board, word, n+1, x-1, y)
||searchexist(board, word, n+1, x, y+1)
||searchexist(board, word, n+1, x, y-1);
//回溯失败,将其重置
board[x][y] = temp;
return flag;
}
};

浙公网安备 33010602011771号