数据结构和算法

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

进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

 
1)递归方式:
// 递归方式
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
解释:不含 “山脉”。

 
动态规划思路:分别找到从前往后和从后往前的最长上升子数组,然后长度加起来,减去1即可
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;
    }

};

  

 

 

 
posted @ 2021-02-20 19:03  静悟生慧  阅读(127)  评论(0编辑  收藏  举报