题目4-6

4 二维数组中的查找

题目描述

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

[
    [ 1,  5,  9],
    [10, 11, 13],
    [12, 13, 15]
]

解题思路

从右上角或左下角开始查找,假设从右上角开始查找,如果待查找的数小于当前位置的数,那么一定在当前位置的左边,即当前位置的下边不可能存在比自己小的数。 同理,如果待查找的数大于当前位置的数,那么一定在当前位置的下边,即当前位置的左边不可能存在比自己大的数。这一原则也就意味着不能从左上角或右下角开始查找, 因为查找的过程中无法做到精准无误的排除不可能区域。

选择从右上角开始查找

class Solution
{
public:
    bool Find(vector<vector<int> > array,int target)
    {
        bool res = false;
        int row = array.size( );
        int col = array[0].size( );

        //  我们从右上角的元素找起来
        //  如果查找的元素比当前位置元素小, 就向左走
        //  如果查找的元素比当前位置元素大, 就向下走
        for(int i = 0, j = col -1;
                (i >=0 && i < row) && (j >= 0 && j < col);)
        {
            if(target == array[i][j])
            {
                res = true;
                break;
            }
            else if(target < array[i][j])     // 小的元素在当前位置左侧
            {
                j--;
            }
            else
            {
                i++;
            }
        }
        return res;
    }
};

利用 python 实现一下

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, array, target):
        row = len(array)
        col = len(array[0])
        res = False
        x = 0
        y = col -1
        while 0 <= x < row and 0 <= y < col:
            if array[x][y] == target:
                res = True
                break
            elif array[x][y] < target:
                x += 1
            else:
                y -= 1
        return res

牛客上利用 python 字符串方法实现的查找

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        n=len(array)
        flag='false'
        for i in range(n):
            if target in array[i]:
                flag='true';
                break
        return flag
while True:
    try:
        S=Solution()
        # 字符串转为list
        L=list(eval(raw_input()))
        array=L[1]
        target=L[0]
        print(S.Find(target, array))
    except:
        break

5 空格替换

题目描述

请实现一个函数,将一个字符串中的空格替换成“%20”。 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

We Are Happy

We%20Are%20Happy

解题思路

思路分为两种,第一是不在原来的字符串上替换,直接新开一个数组然后一次赋值,这个很简单,但我想可能不是出题人希望考察的;第二是在原来的字符串上进行替换 那么因为空格和“%20”的长度不同,就相当于存在一个插入操作。

一种思路是,依次遍历,发现空格就增加字符串长度,然后填入 “%20” 后面的字符全部向前移两位,这样的话如果遇到连续的空格那么就可能会做无用功

另一种思路是,先遍历一遍字符串,统计出空格的数目,这样就知道了替换后字符串的总长度,然后再对字符串进行替换,避免了无用的移动工作。

之所以选择从后往前遍历,是因为如果空格足够多的话,这样的遍历方式在一开始一段时间内是不需要移动的,只需要复制。

/*
一个偷懒的写法,利用 string 的 find 方法实现,最后再转换回 char*
*/
class Solution
{
public:
    void replaceSpace(char *str, int length)
    {
        string a(str);
        int pos = 0;

        while (pos != string::npos)
        {
            pos = a.find(" ", pos);
            if (pos != string::npos)
            {
                a.replace(pos, 1, "%20");
            }
        }
        cout << "fuck" << endl;
        //最后将 string 转换为 char*
        strcpy(str, a.data());
    }
};
/*
笨拙型
*/
#include <iostream>
#include <Windows.h>

using namespace std;

#define __tmain main


class Solution
{
public:
    void replaceSpace(char *str,int length)
    {
        int i = length - 1, j;
        int len = length;

        //  从后往前遍历
        for(i = length - 1; i >= 0; i--)
        {
            //cout <<str[i] <<endl;
            //  如果当前字符是空格
            if(str[i] == ' ')
            {
                //  从空格变成%20长度增加了2
                len += 2;

                for(j = len - 1; j > i + 2; j--)
                {
                    str[j] = str[j - 2];
                }
                str[j--] = '0';
                str[j--] = '2';
                str[j--] = '%';
            }
            //cout <<str <<endl;
        }
        str[len] = '\0';
    }
};


int __tmain( )
{
    char str[10 + 1] = "a b c d";
    Solution solu;
    solu.replaceSpace(str, 10);
    cout <<str <<endl;
    system("pause");
    return 0;
}
// 优化型
#include <iostream>
#include <Windows.h>

using namespace std;

#define __tmain main


class Solution
{
public:
    void replaceSpace(char *str, int length)
    {
        int i, j;
        int count = 0;
        int len = length;
        for(int i = 0; i < length; i++)
        {
            if(str[i] == ' ')
            {
                count++;
            }
        }

        len = length + count * 2;
        for(i = length - 1, j = len - 1;
                i >= 0 && j >= 0;)
        {
            if(str[i] == ' ')
            {
                str[j--] = '0';
                str[j--] = '2';
                str[j--] = '%';
                i--;
            }
            else
            {
                str[j--]  = str[i--];
            }
        }
        str[len] = '\0';
    }
};


int __tmain( )
{
    char str[10 + 1] = "a b c d";
    Solution solu;
    solu.replaceSpace(str, 10);
    cout << str << endl;
    system("pause");
    return 0;
}

python 实现

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s = list(s)
        count=len(s)
        for i in range(0,count):
            if s[i]==' ':
                s[i]='%20'
        return ''.join(s)

6 从尾到头打印链表

题目描述

输入一个链表,从尾到头打印链表每个节点的值。

输入描述:

输入为链表的表头

输出描述:

输出为需要打印的 vector

解题思路

首先我们想到的就是反转链表了,甚至可以利用 reverse 方法,这样再次遍历的时候就相当于从尾到头打印了。

但是修改输入数据真的可行么?在面试时候,如果我们打算修改输入的数据,最好先问问面试官是不是允许修改 通常打印只是一个只读操作,我们肯定不希望输入时候修改链表的内容

1.利用栈的先进后出特性,每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个输出结点的值,此时输出的结点的顺序已经反转过来了。

struct ListNode
{
public:
    int val;
    struct ListNode *next;

    /*ListNode(int x) :
    val(x), next(NULL)
    {
    }*/
};

class Solution
{
public:
    vector<int> printListFromTailToHead(struct ListNode* head)
    {
        ListNode *node = head;
        stack<int> st;
        int count = 0;
        while (node != NULL)
        {
            dout << node->val << " in stack" << endl;
            st.push(node->val);
            count++;
            node = node->next;

        }

        vector<int> res(count);
        dout << "count = " << count << endl;
        for (int i = 0; i < count && st.empty() != true; i++)
        {
            dout << st.top() << " in vector" << endl;
            //res.push_back(st.top( ));
            res[i] = st.top();
            st.pop();
        }
        return res;
    }
};

2.利用递归。因为递归本来就是一个函数压栈的过程,所以很自然的适合此题的场景

class Solution
{
public:
    //利用 递归的实现
    vector<int> res; //因为利用了递归,所以不能定义在函数内部
    vector<int> printListFromTailToHead_0(struct ListNode* head)
    {
        if(head != NULL)
        {
            printListFromTailToHead(head->next);
            res.push_back(head->val);
        }
        return res;
    }
};
  1. 不使用 栈 也不使用 递归,利用链表的头插法的逆序特性

但此方法会改变原链表

class Solution
{
public:
    //利用头插法实现
    vector<int> printListFromTailToHead(struct ListNode* head)
    {
        ListNode *Head = new ListNode;//头节点 即 -1 节点
        Head->next = NULL;
        ListNode *cur = head;
        for (; cur != NULL;)
        {
            ListNode* temp = cur->next;
            cur->next = Head->next;
            Head->next = cur;
            cur = temp;
        }
        Head = Head->next;
        vector<int> array;
        for (; Head != NULL;Head = Head->next)
        {
            array.push_back(Head->val);
        }
        return array;
    }
};