很多时候看到题目,如果你认真的思考,大都会得到一个直观的思路,跟着这个思路做会得到一个结果。但这只是第一步,很多时候first thought的结果并非最优的,甚至会有很多冗余。这个时候我们不能满足于仅仅跑通代码,得到一个预期的输出就ok了。否则我们很难得到有效的进步。我认为我们要再次审题,再次审视自己的代码,看看哪些地方的计算有冗余,可以优化,看看哪些概念可以转换,很多时候你换个角度理解,就会发现不同的角度竟然可以更高效的解决相同的问题。
每道题目都会有多种解法,希望自己在练习时都能深入去思考,思考问题的本质在哪里。当然前提是打好基本功。
好了,唠完开始上题。以下很多题目来自leetcode
常用的数据结构 包括 数组、字符串、链表、队列、栈、树。下面会逐一回顾和举例。
用于按顺序存储元素的集合。元素可以随机存取,因为数组中元素可通过索引访问。存取的时间复杂度为O(1)
数组可以是一维,也可以是多维的。 一维数组也称为线性数组。
以下代码简单说明数组的基本用法
1、数组定义,初始化
int[] a0 = new int[5];
int[] a1 = {1,2,3};
以上为两种初始化方法。
2、数组访问
for(int i=0;i System.out.println( a1[i] ) 以上数组的定义都是固定容量,即初始化时指定了数组大小。这种形式有时很不方便。 因此大多数语言都提供了内置的动态数组,它仍是随机存取的列表数据结构,但大小是可变的。 如c++ 中的vector java中的ArrayList C#中的List<> 以及python中的列表list 以下是一些数组相关的代码编程题,皆来自leetcode 给定一个整数类型的数组 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。 如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。 例如: 为了练习python,以下全部用python语言编写 上述方法,一个是注意enumerate()的用法,迭代时,前面的 i 代表索引,j 代表数组中的值 在一个给定的数组 查找数组中的最大元素是否至少是数组中每个其他数字的两倍。 如果是,则返回最大元素的索引,否则返回-1。 这里也有几个算法之外的注意点:1是 sort() 与 sorted()的区别。sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。sort直接修改list本身,没有返回值,sorted()不修改要排序的可迭代对象,而是返回一个排序好的新的可迭代对象。 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头 实例: 倒叙遍历,也可以通过 reversed 方法或 列表的reverse()方法倒排 二维数组类似,也可以用一维数组的形式来表示,常见例题包括螺旋矩阵、杨辉三角等。 字符串实际上是一个 有些语言中字符串是不可修改的,哪怕只是修改其中一个字符,也只能创建一个新的字符串。像python java都是这样。 python 可使用 replace('a','b')会返回一个新的字符串,也可先把字符串转换为可修改的字符数组或者是字符列表。修改后,再转换为字符串。python中可以使用join()函数 给定两个二进制字符串,返回他们的和(用二进制表示)。 输入为非空字符串且只包含数字 示例 : 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 示例 : 题目三:最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 示例 1: 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 示例 1: 思想很朴素,先得到最短的字符串长度,逐个索引位置 遍历每个字符串,如果全部相等,该位置字符放入列表,若不相等直接返回列表对应的字符串 给定一个字符串,逐个翻转字符串中的每个单词。 示例 1: 这里要注意,不需要指定split()的参数,我之前老是用split(' ')以为这样按空格分隔的来分裂,但这样遇到多个空格时会把空格拆成独立的元素。 而不加参数时,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等分隔。所以这里根本不需要加参数。 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 示例 1: 给定一个数组 示例: 上面是两种常用的解题方法,方法一是经典的快慢指针,快指针寻找到非0的元素就与慢指针交换元素值。 方法二,在循环中删除和添加,有些语言是不支持的,这点python的设计很神奇 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 示例 2: 其实有很多种解法,上面这种是借助字典。 242 数组 字符串 24/25链表题一
nums
,请编写一个能够返回数组“中心索引”的方法。输入:
nums = [1, 7, 3, 6, 5, 6]
输出: 3 解释 :索引3 (nums[3] = 6) 的左侧数之和(1 + 7 + 3 = 11),与右侧数之和(5 + 6 = 11)相等。
同时, 3 也是第一个符合要求的中心索引。
方法一 暴力破解, 遍历所有情况 ,时间复杂度O(n*n)
def pivotIndex(nums):
if nums == None:
return -1
for i in range(len(nums)):
left,right =0,0
for j in range(i):
left += int(nums[j])
for k in range(i+1,len(nums)):
right += int(nums[k])
if left == right:
return i
return -1
#方法一可以解决问题,但显然效率太低,计算有冗余,我们要想办法减少计算冗余,提升算法效率
#方法二 遍历优化,由于每次计算左边的和,或者右边的和时,都要进行累加,仔细思考后发现这其中的重复计算在于,当pivot向右移动时,其实不用每次都全部元素累加,只需保存上次的累加和,左边在上次的基础上加上新的值,而右边只需在上次的基础上减去一个值就可以了。
def pivotIndex(nums):
llast,rlast = 0,sum(nums[1:])
for i in range(len(nums)):
if llast == rlast:
return i
if i == len(nums)-1:
return -1
llast += nums[i]
rlast -= nums[i+1]
return -1
#方法三,进一步优化程序的编写,上述代码略微繁琐
def pivotIndex(nums):
left = 0
total = sum(nums)
for i,j in enumerate(nums):
if left == (total - j )/2:
return i
left += j
return -1
题目二:至少是其他数字两倍的最大数
nums
中,总是存在一个最大元素 。#方法一,也是最朴素的思路,首先找到这个最大值和其索引,然后遍历数组,看是否满足条件
def dominantIndex(nums):
maxval,index = 0,-1
for i,j in enumerate(nums):
if maxval < j:
maxval = j
index = i
for i,j in enumerate(nums):
if index == i:
continue
if maxval < 2*j:
return -1
return index
#方法二 ,借助排序,也是一个常用的技巧。排序后,将最大的元素与第二大的元素进行比较,只要一次即可
if len(nums) == 1:
return 0
nums1 = sorted(nums,reverse=True)
if nums1[0] >= 2*nums1[1]:
return nums.index(nums1[0])
return -1
题目三:加一
输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。
#逻辑其实很简单,就是从低位加1,若和等于10,向高位进一位,继续计算,否则返回该数组
def plusOne(digits):
#首先一个点,是倒叙遍历,这有点不太符合我们的常规操作,但原理是一样的
for i in range(len(digits)-1,-1,-1):
if digits[i] <= 8:
digits[i] += 1
return digits
else:
digits[i] = 0
return [1]+digits
二、字符串
unicode 字符
数组。你可以执行几乎所有我们在数组中使用的操作。题目一:二进制求和
1
和 0
。输入: a = "11", b = "1"
输出: "100"
def addBinary(a,b):
return bin(int(a,2)+int(b,2))[2:]
这里主要是记住两个python内置函数 int()它不单单是强制把参数转换为int类型,还可以接受第二参数,代表要转换的数是多少进制。向本题int(a,2)就是把a当做是2进制数,转换为10进制的整型。最后通过bin 把10进制数再转换为2进制。
题目二: 实现 strStr()函数
输入: haystack = "hello", needle = "ll"
输出: 2
def strStr(self, haystack: str, needle: str) -> int:
#方法一,直接调用api
#return haystack.find(needle)
#方法二,遍历
len1 = len(haystack)
len2 = len(needle)
if len1 < len2:
return -1
start,end = 0,len2-1
while end < len1:
substr = haystack[start:end+1]
if substr == needle:
return start
start += 1
end += 1
return -1
""
。输入: ["flower","flow","flight"]
输出: "fl"
题目三:最长公共前缀
""
。输入: ["flower","flow","flight"]
输出: "fl"
def longestCommonPrefix(strs: List[str]) -> str:
if len(strs) == 0:
return ""
result = []
index = 0
minLen = 9999
for item in strs:
if len(item) < minLen:
minLen = len(item)
while index < minLen:
for item in strs:
if strs[0][index] != item[index]:
return "".join(result)
result.append(strs[0][index])
index += 1
return "".join(result)
题目四:翻转字符串里的单词
输入: "
the sky is blue
"
输出: "blue is sky the
"def reverseWords(s: str):
return ' '.join(s.split()[::-1])
题目五:反转字符串中的单词 III
输入: "Let's take LeetCode contest"
输出: "s'teL ekat edoCteeL tsetnoc"
def reverseWords(s: str) -> str:
li = s.split()
return ' '.join(map(lambda x:x[::-1],li))
题目六:移动零
nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。输入:
[0,1,0,3,12]
输出: [1,3,12,0,0]
#解法一,快慢指针
def moveZeroes(nums) -> None:
slow = 0
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow], nums[fast] = nums[fast], nums[slow]
slow += 1
def MoveZero(nums):
for num in nums:
if num == 0:
nums.remove(0) #remove方法删除列表中第一个0元素
nums.append(0) #末尾加一个0
题目 七 :有效的字母异位词
输入: s = "anagram", t = "nagaram"
输出: true
输入: s = "rat", t = "car"
输出: false
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False
dic1,dic2 = {},{}
for item in s:
if item not in dic1:
dic1[item] = 1
else:
dic1[item] += 1
for item in t:
if item not in dic2:
dic2[item] = 1
else:
dic2[item] += 1
if dic1 == dic2:
return True
else:
return False