zoukankan      html  css  js  c++  java
  • leetcode刷题笔录1

    1. 回文分割

    • 给定一个字符串s,将s分割为数个子串,每个子串都是回文。
      比如,给定字符串"aab",返回:
      [
          ["aa","b"],
          ["a","a","b"]   
      ]
    • 思路:递归法,子串 s[i]...s[j] 的所有回文分割,都是由 s[1] 单独构成的一个元素的子串连接上 s[2]...s[j] 的所有回文分割(子问题),以及任何一个回文子串 s[1]...s[k] 连接上上 s[k+1]...s[j] 的回文分割(子问题)
    • 实现:
      class Solution {
      public:
          vector<vector<string>> partition(string s);
      private:
          vector<vector<string>> _partition(const string& s, const int i, const int j);
          vector<string> addhead(const vector<string>& list, const string& head);
          bool isPal(const string& s, const int i, const int j);
          vector<vector<int>> pals;
      };
      
      vector<vector<string>> Solution::partition(string s) {
          int n = s.size();
          pals = vector<vector<int>>(n, vector<int>(n, 0));
          return _partition(s, 0, n-1);
      }
      
      vector<vector<string>> Solution:: _partition(const string& s, const int i, const int j){
          vector<vector<string>> list;
          if(i==j){
              string tmp(1, s[i]);
              list.push_back(vector<string>(1, tmp));
              return list;
          }
          for(int p=i; p<j; p++){
              if(isPal(s,i,p)){
                  vector<vector<string>> _list = _partition(s, p+1, j);
                  string _head = s.substr(i,p-i+1);
                  for(int k=0; k<=_list.size()-1; k++){
                      vector<string> tmp = addhead(_list[k],_head);
                      list.push_back(tmp);
                  }
              }
          }
          if(isPal(s,i,j)){
              list.push_back(vector<string>(1, s.substr(i,j-i+1)));
          }
          return list;
      }
      
      vector<string> Solution::addhead(const vector<string>& list, const string& head){
          vector<string> rs;
          rs.push_back(head);
          for(int i=0; i<=list.size()-1; i++){
              rs.push_back(list[i]);
          }
          return rs;
      }
      
      bool Solution::isPal(const string& s, const int i, const int j){             
          if(i>=j){
              return true;
          }
          if(pals[i][j]!=0){
              return pals[i][j]>0 ? true : false;
          }    
          if(s[i]==s[j]){
              bool _isPal = isPal(s, i+1, j-1);
              pals[i][j] = _isPal ? 1 : -1;
              return _isPal;
          }
          else{
              pals[i][j] = -1;
              return false;
          }
      }  

    2. 回文分割2

    • 给定一个字符串s,将s分割为数个子串,每个子串都是回文。
      返回将字符串回文分割最少分割次数。
      比如,给定字符串"aab",返回1,因为分割["aa","b"]可由一个分割(逗号)生成。
    • 思路:动态规划,维护两个二维表,分别表示子串 s[i]...s[j] 是否是回文,以及最少回文分割次数(如果子串本身是回文,这个域就是0)。子串的最小回文分割次数就是 s[i]...s[k] 和 s[k+1]...s[j] 的最小回文分割次数之和(两个子问题的和)加1,在区间[i,j]取一个k值使该结果最小。
    • 实现:
      class Solution {
      public:
          int minCut(string s);
      
      private:
          int _minCut(const string& s, const int i, const int j);    
          bool isPal(const string& s, const int i, const int j);
          
          vector<vector<int>> mcTable;
          vector<vector<int>> isPalTable; // 1 for true, -1 for false, 0 for uncertain
      };
      
      int Solution::minCut(string s){
          int n = s.size();
          mcTable = vector<vector<int>>(n, vector<int>(n,-1));
          isPalTable = vector<vector<int>>(n, vector<int>(n, 0));
          return _minCut(s, 0, n-1);
      }
      
      int Solution::_minCut(const string& s, 
                              const int i, 
                              const int j){
                          
          if(mcTable[i][j] != -1){
              return mcTable[i][j];
          }
          else{
              if(isPal(s,i,j)){
                  mcTable[i][j]=0;
                  return 0;
              }
              else{
                  int min = INT_MAX;
                  for(int k=i; k<=j-1; k++){
                      int cutNums = _minCut(s,i,k) + _minCut(s,k+1,j) + 1;
                      if(cutNums<min){
                          min = cutNums;
                      }
                  }
                  mcTable[i][j]=min;
                  return min;
              }
          }
      }
      
      bool Solution::isPal(const string& s,
                              const int i, 
                              const int j){
                                  
          if(i>=j){
              return true;
          }
          if(isPalTable[i][j] != 0){
              return isPalTable[i][j]>0 ? true : false;
          }
          else{
              if(s[i]!=s[j]){
                  isPalTable[i][j]=-1;
                  return false;
              }
              else{
                  if(isPal(s,i+1,j-1)){
                      isPalTable[i][j]=1;
                      return true;
                  }
                  else{
                      isPalTable[i][j]=-1;
                      return false;
                  }
              }
          }
      }

    3. 围棋

    • 给定一块二维棋盘,每一个格子要么是'X'要么是'O'。将所有被'X'围起来(像围棋一样围起来)'O',都转变为'O'。
      比如,给定:
      X X X X
      X O O X
      X X O X
      X O X X

      返回:

      X X X X
      X X X X
      X X X X
      X O X X
    • 思路:四条边上的'O'是不会被围起来的,与他们相邻的'O'也不会被围起来。该性质可以传递下去,类似于“感染”。那么就将四边上的'O'感染为'A',再递归地感染相邻的'O',完成之后将未被感染的'O'转为'X',再将'A'转为'O'。
    • 实现:
      class Solution {
      public:
          void solve(vector<vector<char>> &board);
      private:
          void infect(vector<vector<char>>& board, int i, int j);
      };
      
      void Solution::solve(vector<vector<char>> &board) {
          int n = board.size();
          if(n==0){
              return;
          }
          int m = board[0].size();
          for (int i=0; i<=n-1; i++){
              if (board[i][0]=='O'){
                  infect(board, i, 0);
              }
              if (board[i][m-1]=='O'){
                  infect(board, i, m-1);
              }
          }
          for (int j=0; j<=m-1; j++){
              if (board[0][j]=='O'){
                  infect(board, 0, j);
              }
              if (board[n-1][j]=='O'){
                  infect(board, n-1, j);
              }
          }
      
          for (int i=0; i<=n-1; i++){
              for (int j=0; j<=m-1; j++){
                  if (board[i][j]=='O'){
                      board[i][j]='X';
                  }
              }
          }
      
          for (int i=0; i<=n-1; i++){
              for (int j=0; j<=m-1; j++){
                  if (board[i][j]=='A'){
                      board[i][j]='O';
                  }
              }
          }
      }
      
      void Solution::infect(vector<vector<char>>& board, int i, int j){
          board[i][j] = 'A';
          int n = board.size();
          int m = board[0].size();
          if(i!=0 && board[i-1][j]=='O'){
              infect(board, i-1, j);
          }
          if(i!=n-1 && board[i+1][j]=='O'){
              infect(board, i+1, j);
          }
          if(j!=0 && board[i][j-1]=='O'){
              infect(board, i, j-1);
          }
          if(j!=m-1 && board[i][j+1]=='O'){
              infect(board, i, j+1);
          }
      }

    4. “根-叶”数之和

    • 给定一个二叉树,每个树的节点值都为 0~9 的整数。每一个从根节点到叶节点的路径代表一个整数。
      比如,路径 1-2-3 代表整数 123。找到二叉树所有从根节点到叶节点的路径的“根-叶”数之和。
      比如,给定:
          1
         / \
        2   3

       1-2路径表示12,1-3路径表示13,那么应当返回12+13=25。

    • 思路:进入每一棵子树时,传入一个从根节点开始累积的值,到达叶节点后将改值加到全局变量sum上,如路径 1-2-3 : 1-(1)-2-(12)-3(123)-sum+=123。这样就仍可以自然地进行递归迭代,而不用写二叉树的迭代遍历。
    • 实现:
      /**
       * Definition for binary tree
       * struct TreeNode {
       *     int val;
       *     TreeNode *left;
       *     TreeNode *right;
       *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
       * };
       */
      class Solution {
      public:
          int sumNumbers(TreeNode *root) {
              sum = 0;
              _sumNumbers(root, 0);
              return sum;
          }
      private:
          void _sumNumbers(TreeNode* root, int rootVal){
              if (root==NULL){
                  return;
              }
              int val = rootVal*10+root->val;
              if (root->left==NULL && root->right==NULL){
                  sum += val;
              }
              _sumNumbers(root->left, val);
              _sumNumbers(root->right, val);
          }
          int sum;
      }; 

    5. 最长连续序列

    • 给定一个未排序的整数数组,找到最长连续序列的长度。
      比如,给定[100,4,200,1,3,2],应当返回4,因为最长连续序列为[1,2,3,4],其长度为4。
      算法的时间代价应当为O(n)。
    • 思路:规定了O(n)的时间复杂度,想到使用哈希表。使用哈希集合st来滤掉重复的元素,哈希表mp中维护着这样的结构:所有已考虑的元素组成的连续序列的两端,键为两端的位置,值为另一端的位置。如果序列仅有一个元素(如考虑第一个元素时),则两端都是它自身,它的值指向它自己。由于st的帮助,所有新考虑的值都不会出现在连续序列中。
    • 实现:
      class Solution {
      public:
          int longestConsecutive(vector<int> &num) {
              hash_map<int, int> mp;
              hash_set<int> st;
              int max = 0;
              for (int i=0; i<=num.size()-1; i++){
                  if (st.find(num[i])!=st.end()){
                      continue;
                  }
                  st.insert(num[i]);
                  int tleft = num[i];
                  int tright = num[i];
                  if (mp.find(tleft-1)!=mp.end()){
                      tleft = mp[tleft-1];
                  }
                  if (mp.find(tright+1)!=mp.end()){
                      tright = mp[tright+1];
                  }
                  int len = tright-tleft+1;
                  max = max<len ? len : max;
                  mp[tleft] = tright;
                  mp[tright] = tleft;
              }
              return max;
          }
      };
    作者:一叶斋主人
    出处:www.cnblogs.com/yiyezhai
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Spring学习之旅(二)--容器
    Spring学习之旅(一)--初始Spring
    Logback的使用
    DES加解密工具类
    Lombok插件的使用
    from 表单用 GET 方法进行 URL 传值时后台无法获取问题
    组播
    linux头文件路径
    IANA
    6号板获取或放文件
  • 原文地址:https://www.cnblogs.com/yiyezhai/p/2964970.html
Copyright © 2011-2022 走看看