zoukankan      html  css  js  c++  java
  • 数据结构和算法

    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;
        }
    
    };
    

      

     
  • 相关阅读:
    LINUX中常用操作命令
    NET Core Kestrel部署HTTPS
    Java中Enum枚举的使用
    Java多线程——sychronized
    Java中SynchronizedMap与ConcurrentHashMap的对比
    Java中HashMap实现原理
    数据结构——Java实现单向链表
    数据库——事务基础
    数据结构——Java实现二叉树
    Java中ThreadLocal的深入理解
  • 原文地址:https://www.cnblogs.com/Allen-rg/p/14422852.html
Copyright © 2011-2022 走看看