刷题整理笔记。

最小编辑距离

链接地址

leetcode 版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<iostream>
#include<vector>

using namespace std;
class Solution {
public:
    int minDistance(string word1, string word2) {
        int rows = word1.length();
        int cols = word2.length();
        vector<vector<int> > dp(rows+1, vector<int>(cols+1, 0));
        
        for(int i=1; i<=rows; ++i)
            dp[i][0] = i;
        for(int j=1; j<=cols; ++j)
            dp[0][j] = j;
        
        for(int i=1; i<=rows; ++i){
            for(int j=1; j<=cols; ++j){
                if(word1[i-1] == word2[j-1])
                    dp[i][j] = dp[i-1][j-1];
                else
                    dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1])) + 1;
            }
        }
        
        return dp[rows][cols];
    }
};

int main()
{
    Solution solution;
    
    string str1 ="hello";
    string str2 ="hello1";
    cout << solution.minDistance(str1, str2) << endl;
    
    
    return 0;

}

单机版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

/**
使用dp 的思想,
 f[i][j] 表示string1中第i 个位置和 string2 中第j 位置之间的最小编辑距离
 转移: f[i][j] =f[i-1][j-1] if string1[i] ==string2[j]
  = min(f[i-1][j], f[i][j-1] ) 对应的是修改
 初始化: f[0][0] =1, 然后f[i][0] 和 f[0][j] 都是0, 最后的f[m][n]  就是最后的结果
 
 **/
int main()
{
    string str1, str2;
    cin >> str1>> str2;

    int n,m;
    n =str1.size(), m =str2.size();
    
    vector<vector<int>> f(n+1, vector<int>(m+1));
    
    // 初始化需要根据实际意义进行
    f[0][0] =0;
    
    for(int i =1; i<=n; i++) f[i][0] =i;
    for(int j =1; j<=m ;j++) f[0][j] =j;
        
    
    for(int i =1; i<=n; i++)
    {
        for(int j =1; j<=m; j++)
        {
            //if(!i ||!j) f[i][j] =0;
            if(str1[i] ==str2[j]) f[i][j] =f[i-1][j-1];
            else
            {
                f[i][j] =min(f[i-1][j-1], min(f[i-1][j], f[i][j-1]))+1;
            }
            
            
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

python 语言实现

注意两种初始化的区别:

1
2
    dp =[(cols+1)*[0]]*(rows+1) # 这种是不 work 的
    dp =[ [0] *(cols+1) for _ in range(rows+1)] # 这种是 work 的
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def minDistance(string1, string2):

    if not string1 or not string2 : return


    rows, cols =len(string1), len(string2)
    if rows ==0: return cols;
    elif cols ==0: return rows;

    #dp =[(cols+1)*[0]]*(rows+1)
    dp =[ [0] *(cols+1) for _ in range(rows+1)]



    for i in range(1, rows+1): dp[i][0] =i
    for j in range(1, cols+1): dp[0][j] =j

    #ipdb.set_trace()

    for i in range(1, rows+1):
        for j in range(1, cols+1):

            if string1[i-1] ==string2[j-1]:
                dp[i][j] =dp[i-1][j-1]
            else:
                dp[i][j] =1 + min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])

    return dp[-1][-1]

print(minDistance("string1", "string"))

** 从无头单链表中删除节点**

删除节点的通常做法是找到该结点的前一个结点(头结点),然后 head.next =head.next.next 这个题目说没有头结点,直接给出的就是应该删除的结点 假设这个是头结点,那么下一个是待删除的结点,所以 current.next =current.next.next ,但是需要把current.next.value 赋值给 current.value

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef struct node{
    int data;
    node *next;
}Node;

void delete_node(Node *current)
{
    assert(current !=NULL);
    
    Node *next =current->next;
    
    if (next !=NULL)
    {
        current->next =next->next
        current-> data =next-> data;
        
    }
}

int main()
{
    return 0;
}

38. Count and Say

https://leetcode.com/problems/count-and-say/

leetcode 版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    string countAndSay(int n) {
        string s ="1";
        
        for(int i =0; i<n -1; i++)
        {
            
            string ns;
            for(int j =0; j< s.size();j++ )
            {
                int k =j;
                while(s[k] ==s[j]) k++;
                ns += to_string(k-j)+ s[j];
                j =k -1;
                
            }
            s =ns;
        }
        
        return s;
    }
};

单机版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<iostream>
#include<string>
#include<algorithm>

using namespace std;

string count_say(int n)
{
    string s ="1";
    
    for(int i =0; i<n-1; i++)
    {
        string ns;
        
        for(int j =0; j<s.size(); j++)
        {
            int k =j;
            while( s[k] ==s[j]) k++;
            ns += to_string(k-j)+s[j];
            j = k-1;
        }
        s =ns;
        
    }
    return s;
}

int main()
{
    int n;
    cin >>n;
    
    cout<< count_say(n)<<endl;
    
    return 0;
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
    // 单词不同组合的本质,然后使用dictionary 进行存储
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        
        unordered_map<string, vector<string>> hash;
        
        
        for(auto str: strs)
        {
            string tmp =str;
            sort(tmp.begin(), tmp.end());
            hash[tmp].push_back(str);
        }
        // 本质 -> 现象
        //for(auto item: hash) cout<<item<<endl;
        

        vector<vector<string>> res;
        for(auto item: hash) res.push_back(item.second);
        return res;

        
    }

};

https://leetcode.com/problems/group-anagrams/submissions/

vector中push_back 类似 python 中list 的append 操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<unordered_map>

using namespace std;

// 单词打错了,也是不通过的
vector<vector<string>> group(vector<string>& input)
{
    // 还原本质,
    unordered_map<string, vector<string>> dict; // map 的底层实现是平衡树,操作的时间复杂度是logn, 所以慢,而unordered_map(hash表) 是常数
    
    
    for(auto str : input)
    {
        string tmp =str;
        sort(tmp.begin(), tmp.end());
        dict[tmp].push_back(str);
        
    }
    // 结果
    
    vector<vector<string>> res;
    
    for(auto key: dict) res.push_back(key.second);
    
    return res;
}

int main()
{
    int n ;
    cin>>n;
    vector<string> input;
    for(int i =0; i<n;i++)
    {
        string tmp ;
        cin >>tmp;
        input.push_back(tmp);
        
    }
    
    vector<vector<string>> res =group(input);
    
    for(auto u: res)
    {
        for(auto v: u)
            cout<< v<<" ";
        cout<<endl;
        
    }

    
    return 0;
}



Two sum 系列套题

有多对解,输出一对解就可以。最简单的一种情况。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<iostream>
#include<unordered_set>
#include "vector"
using namespace  std;

#define LEN 100
vector<int> nums(LEN);

vector<int> find_sum(vector<int> & nums, int target)
{
    unordered_set<int> hash;
    
    for(int i =0; i<nums.size(); i++)
    {
        if(hash.count(target -nums[i] )) return vector<int>{target-nums[i], nums[i]};
        hash.insert(nums[i]);
    }
    return vector<int>();
    
}

int main()
{

    int n , target;
    cin >>n >> target;
    

    for(int i =0; i<n; i++)
        cin>> nums[i];
    
    vector<int> res =find_sum(nums, target);
    
    for(int i =0; i<res.size(); i++)
        cout<< res[i]<<" ";
    cout<<endl;
    
    
    return 0;
}

逆序对

暴力求解,时间复杂度是$O(N^2)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
public:
    int InversePairs(vector<int> data) {
        int n =data.size();
        // 先是暴力求解 理解一下题意
        int res =0;
        for(int i =0; i<n; i++)
        {
            for(int j =i+1; j<n; j++)
                if(data[i] >data[j]) res +=1;
        }
        return res;
    }
};

这个在牛客网上,使用归并的方式,也是没有办法完全通过,只能保证是 50% 的case。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
    // 归并排序 时间复杂度 O(nlogn), 对于当前的区间分成左区间的结果,右区间的结果和两个区间之间的结果
    // 递归的思想就是要递归跳出的条件
    int merge(vector<int>& data, int l, int r)
    {
        if(l >=r) return 0;
        int mid =l +r >>1;
        
        int res= merge(data, l, mid) +merge(data, mid+1, r); 
        int i =l, j =mid+1;
        vector<int> temp;
  
        while( i<=mid && j<=r)
        {
            if(data[i]< data[j]) temp.push_back(data[i++]);
            else
            {
                res += mid -i+1;
                temp.push_back(data[j++]);
            }
        }
        while(i<=mid) temp.push_back(data[i++]);
        while(j <=r) temp.push_back(data[j++]);
        // 这个是当前区间的起点
        i =l;
        for(auto u: temp) data[i++] =u;
        return res % 1000000007;
    }
    int InversePairs(vector<int> data) {
        return merge(data, 0, data.size()-1);
        
    }
};