From 397cdacc215f3a3248d5d7506f993a35753912a5 Mon Sep 17 00:00:00 2001 From: Jnewgeek <912422378@qq.com> Date: Thu, 1 Apr 2021 21:26:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BB=83=E4=B9=A0=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../数据结构与算法(上)-checkpoint.ipynb | 838 ++++++++++++++++++ .../数据结构与算法(上).ipynb | 838 ++++++++++++++++++ 2 files changed, 1676 insertions(+) create mode 100644 DataStructureAndAlgorithm/.ipynb_checkpoints/数据结构与算法(上)-checkpoint.ipynb create mode 100644 DataStructureAndAlgorithm/数据结构与算法(上).ipynb diff --git a/DataStructureAndAlgorithm/.ipynb_checkpoints/数据结构与算法(上)-checkpoint.ipynb b/DataStructureAndAlgorithm/.ipynb_checkpoints/数据结构与算法(上)-checkpoint.ipynb new file mode 100644 index 0000000..d8ed7e0 --- /dev/null +++ b/DataStructureAndAlgorithm/.ipynb_checkpoints/数据结构与算法(上)-checkpoint.ipynb @@ -0,0 +1,838 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task01:数组(1天)\n", + "理论部分\n", + "\n", + "- 理解数组的存储与分类。\n", + "- 实现动态数组,该数组能够根据需要修改数组的长度。\n", + "\n", + "**1. 利用动态数组解决数据存放问题**\n", + "\n", + "编写一段代码,要求输入一个整数N,用动态数组A来存放2~N之间所有5或7的倍数,输出该数组。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5,7,10,14,15,20,21,25,28,30,35,40,42,45,49,50,55,56,60,63,65,70,75,77,80,84,85,90,91,95,98,100," + ] + } + ], + "source": [ + "def dynamiclist(N):\n", + " if N < 2:\n", + " return []\n", + " return filter(lambda x:x % 5 == 0 or x % 7 == 0, range(2,N+1))\n", + "\n", + "nums = dynamiclist(100)\n", + "for i in nums:\n", + " print(i, end = ',')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2. 托普利茨矩阵问题**\n", + "\n", + "https://leetcode-cn.com/problems/toeplitz-matrix/\n", + "\n", + "如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。\n", + "\n", + "给定一个M x N的矩阵,当且仅当它是托普利茨矩阵时返回True。" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "输入:\n", + "matrix = [\n", + " [1,2,3,4],\n", + " [5,1,2,3],\n", + " [9,5,1,2]\n", + "]\n", + "输出: True\n", + "解释:\n", + "在上述矩阵中, 其对角线为:\n", + "\"[9]\", \"[5, 5]\", \"[1, 1, 1]\", \"[2, 2, 2]\", \"[3, 3]\", \"[4]\"。\n", + "各条对角线上的所有元素均相同, 因此答案是`True`。\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "说明:\n", + "- matrix 是一个包含整数的二维数组。\n", + "- matrix 的行数和列数均在 [1, 20]范围内。\n", + "- matrix[i][j] 包含的整数在 [0, 99]范围内。\n", + "\n", + "进阶:\n", + "- 如果矩阵存储在磁盘上,并且磁盘内存是有限的,因此一次最多只能将一行矩阵加载到内存中,该怎么办?\n", + "- 如果矩阵太大以至于只能一次将部分行加载到内存中,该怎么办?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def toeplitz_mat(matrix):\n", + " if not matrix or not matrix[0]:\n", + " return False\n", + " for i in range(1, len(matrix)):\n", + " for j in range(1, len(matrix[0])):\n", + " if matrix[i][j] != matrix[i - 1][j - 1]:\n", + " return False\n", + " return True\n", + "\n", + "matrix = [[1,2,3,4],\n", + " [5,1,2,3],\n", + " [9,5,1,2]]\n", + "toeplitz_mat(matrix)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matrix = [[1,2],\n", + " [2,2]]\n", + "toeplitz_mat(matrix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3.三数之和**\n", + "\n", + "https://leetcode-cn.com/problems/3sum/\n", + "\n", + "给定一个包含 n 个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a + b + c = 0?找出所有满足条件且不重复的三元组。\n", + "\n", + "注意:答案中不可以包含重复的三元组。\n", + "\n", + "示例:\n", + "\n", + "```\n", + "给定数组 nums = [-1, 0, 1, 2, -1, -4],\n", + "\n", + "满足要求的三元组集合为:\n", + "[\n", + " [-1, 0, 1],\n", + " [-1, -1, 2]\n", + "]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[-1, -1, 2], [-1, 0, 1]]\n" + ] + } + ], + "source": [ + "def threesum(nums, target = 0):\n", + " if len(nums) < 3:\n", + " return []\n", + " nums.sort()\n", + " res = []\n", + " for i in range(len(nums) - 2):\n", + " if nums[i] > target:\n", + " return res\n", + " if i > 0 and nums[i] == nums[i - 1]:\n", + " continue\n", + " l, r = i + 1, len(nums) - 1\n", + " while l < r:\n", + " sum_ = nums[i] + nums[l] + nums[r]\n", + " if sum_ < target:\n", + " l += 1\n", + " elif sum_ > target:\n", + " r -= 1\n", + " else:\n", + " res.append([nums[i], nums[l], nums[r]])\n", + " while l < r and nums[l] == nums[l+1]:\n", + " l += 1\n", + " while l < r and nums[r] == nums[r-1]:\n", + " r -= 1\n", + " l += 1\n", + " r -= 1\n", + " return res\n", + " \n", + "nums = [-1, 0, 1, 2, -1, -4]\n", + "print(threesum(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task02:顺序表和链表\n", + "理论部分\n", + "\n", + "- 理解线性表的定义与操作。\n", + "- 实现顺序表。\n", + "- 实现单链表、循环链表、双向链表。\n", + "\n", + "**1.合并两个有序链表**\n", + "\n", + "https://leetcode-cn.com/problems/merge-two-sorted-lists/\n", + "\n", + "将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。\n", + "\n", + "示例:\n", + "\n", + "```\n", + "输入:1->2->4, 1->3->4\n", + "输出:1->1->2->3->4->4\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->1->2->3->4->4" + ] + } + ], + "source": [ + "# 链表定义\n", + "class ListNode:\n", + " def __init__(self, val, nextnode = None):\n", + " self.val = val\n", + " self.next = nextnode\n", + " \n", + "# 生成链表\n", + "def generate(nums):\n", + " head = cur = ListNode(-1)\n", + " for i in nums:\n", + " cur.next = cur = ListNode(i)\n", + " return head.next\n", + "\n", + "# 递归\n", + "def mergelist(head_1, head_2):\n", + " if not head_1:\n", + " return head_2\n", + " elif not head_2:\n", + " return head_1\n", + " elif head_1.val < head_2.val:\n", + " head_1.next = mergelist(head_1.next, head_2)\n", + " return head_1\n", + " else:\n", + " head_2.next = mergelist(head_1, head_2.next)\n", + " return head_2\n", + " \n", + "nums1, nums2 = [1,2,4], [1,3,4]\n", + "nums1, nums2 = generate(nums1), generate(nums2)\n", + "head = mergelist(nums1, nums2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->1->2->3->4->4" + ] + } + ], + "source": [ + "# 哑结点\n", + "def mergelist_1(head_1, head_2):\n", + " head = cur = ListNode(-1)\n", + " while head_1 and head_2:\n", + " if head_1.val < head_2.val:\n", + " cur.next, head_1 = head_1, head_1.next\n", + " else:\n", + " cur.next, head_2 = head_2, head_2.next\n", + " cur = cur.next\n", + " cur.next = head_1 if head_1 else head_2\n", + " return head.next\n", + "\n", + "nums1, nums2 = [1,2,4], [1,3,4]\n", + "nums1, nums2 = generate(nums1), generate(nums2)\n", + "head = mergelist_1(nums1, nums2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2. 删除链表的倒数第N个节点**\n", + "\n", + "https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/\n", + "\n", + "给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。\n", + "\n", + "示例:\n", + "```\n", + "给定一个链表: 1->2->3->4->5, 和 n = 2.\n", + "\n", + "当删除了倒数第二个节点后,链表变为 1->2->3->5.\n", + "说明:给定的 n 保证是有效的。\n", + "\n", + "进阶:你能尝试使用一趟扫描实现吗?\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->3->4" + ] + } + ], + "source": [ + "# 2次扫描\n", + "def deletenode(head, n):\n", + " cur, ans = head, 0\n", + " while cur:\n", + " ans += 1\n", + " cur = cur.next\n", + " dummy = cur = ListNode(-1, head)\n", + " for i in range(ans - n):\n", + " cur = cur.next\n", + " cur.next = cur.next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1, 6))\n", + "head = deletenode(nums, 1)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->4->5" + ] + } + ], + "source": [ + "# 1次扫描 空间换时间\n", + "def deletenode_1(head, n):\n", + " hash_map = {}\n", + " cur = dummy = ListNode(-1, head)\n", + " ans = 0\n", + " while cur:\n", + " ans += 1\n", + " hash_map[ans] = cur\n", + " cur = cur.next\n", + " # 被删除的节点索引\n", + " index = ans - n\n", + " hash_map[index].next = hash_map[index].next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1,6))\n", + "head = deletenode_1(nums, 3)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->3->5" + ] + } + ], + "source": [ + "# 栈实现\n", + "def deletenode_2(head, n):\n", + " dummy = cur = ListNode(-1, head)\n", + " stack = []\n", + " while cur:\n", + " stack.append(cur)\n", + " cur = cur.next\n", + " for i in range(n):\n", + " stack.pop()\n", + " prev = stack[-1]\n", + " prev.next = prev.next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1,6))\n", + "head = deletenode_2(nums, 2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3. 旋转链表**\n", + "\n", + "https://leetcode-cn.com/problems/rotate-list/\n", + "\n", + "给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。\n", + "\n", + "示例 1:\n", + "```\n", + "输入: 1->2->3->4->5->NULL, k = 2\n", + "输出: 4->5->1->2->3->NULL\n", + "\n", + "解释:\n", + "向右旋转 1 步: 5->1->2->3->4->NULL\n", + "向右旋转 2 步: 4->5->1->2->3->NULL\n", + "```\n", + "\n", + "示例2:\n", + "```\n", + "输入: 0->1->2->NULL, k = 4\n", + "输出: 2->0->1->NULL\n", + "\n", + "解释:\n", + "向右旋转 1 步: 2->0->1->NULL\n", + "向右旋转 2 步: 1->2->0->NULL\n", + "向右旋转 3 步: 0->1->2->NULL\n", + "向右旋转 4 步: 2->0->1->NULL\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4->5->1->2->3" + ] + } + ], + "source": [ + "# 首先建立循环链表\n", + "def rotate(head, k):\n", + " cur, n = head, 1\n", + " while cur.next:\n", + " cur = cur.next\n", + " n += 1\n", + " cur.next = head\n", + " \n", + " new_tail = head\n", + " for i in range(n - k%n - 1):\n", + " new_tail = new_tail.next\n", + " new_head = new_tail.next\n", + " new_tail.next = None\n", + " return new_head\n", + "\n", + "nums, k = generate(range(1,6)), 2\n", + "head = rotate(nums, k)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task03:栈与递归\n", + "**理论部分**\n", + "\n", + "- 用数组实现一个顺序栈。\n", + "- 用链表实现一个链栈。\n", + "- 理解递归的原理。\n", + "\n", + "**1. 根据要求完成车辆重排的程序代码**\n", + "\n", + "假设一列货运列车共有n节车厢,每节车厢将停放在不同的车站。假定n个车站的编号分别为1至n,货运列车按照第n站至第1站的次序经过这些车站。车厢的编号与它们的目的地相同。为了便于从列车上卸掉相应的车厢,必须重新排列车厢,使各车厢从前至后按编号1至n的次序排列。当所有的车厢都按照这种次序排列时,在每个车站只需卸掉最后一节车厢即可。\n", + "\n", + "我们在一个转轨站里完成车厢的重排工作,在转轨站中有一个入轨、一个出轨和k个缓冲铁轨(位于入轨和出轨之间)。图(a)给出一个转轨站,其中有k个(k=3)缓冲铁轨H1,H2 和H3。开始时,n节车厢的货车从入轨处进入转轨站,转轨结束时各车厢从右到左按照编号1至n的次序离开转轨站(通过出轨处)。在图(a)中,n=9,车厢从后至前的初始次序为5,8,1,7,4,2,9,6,3。图(b)给出了按所要求的次序重新排列后的结果。" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task04:队列\n", + "**理论部分**\n", + "\n", + "- 用数组实现一个顺序队列。\n", + "- 用数组实现一个循环队列。\n", + "- 用链表实现一个链式队列。\n", + "\n", + "**1. 模拟银行服务完成程序代码。**\n", + "\n", + "目前,在以银行营业大厅为代表的窗口行业中大量使用排队(叫号)系统,该系统完全模拟了人群排队全过程,通过取票进队、排队等待、叫号服务等功能,代替了人们站队的辛苦。\n", + "\n", + "排队叫号软件的具体操作流程为:\n", + "\n", + "- 顾客取服务序号\n", + "\n", + "当顾客抵达服务大厅时,前往放置在入口处旁的取号机,并按一下其上的相应服务按钮,取号机会自动打印出一张服务单。单上显示服务号及该服务号前面正在等待服务的人数。\n", + "\n", + "- 服务员工呼叫顾客\n", + "\n", + "服务员工只需按一下其柜台上呼叫器的相应按钮,则顾客的服务号就会按顺序的显示在显示屏上,并发出“叮咚”和相关语音信息,提示顾客前往该窗口办事。当一位顾客办事完毕后,柜台服务员工只需按呼叫器相应键,即可自动呼叫下一位顾客。\n", + "\n", + "编写程序模拟上面的工作过程,主要要求如下:\n", + "\n", + "- 程序运行后,当看到“请点击触摸屏获取号码:”的提示时,只要按回车键,即可显示“您的号码是:XXX,您前面有YYY位”的提示,其中XXX是所获得的服务号码,YYY是在XXX之前来到的正在等待服务的人数。\n", + "- 用多线程技术模拟服务窗口(可模拟多个),具有服务员呼叫顾客的行为,假设每个顾客服务的时间是10000ms,时间到后,显示“请XXX号到ZZZ号窗口!”的提示。其中ZZZ是即将为客户服务的窗口号。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开启服务:S01\n", + "\n", + "开启服务:S02\n", + "\n", + "开启服务:S03\n", + "Y0001\n", + "Y0002\n", + "Y0003\n", + "Y0004\n", + "Y0005\n", + "\n", + "请Y0001号到S03号窗口!\n", + "\n", + "请Y0002号到S02号窗口!\n", + "\n", + "请Y0003号到S01号窗口!\n", + "\n", + "请Y0004号到S03号窗口!\n", + "\n", + "请Y0005号到S02号窗口!\n", + "\n", + "退出服务:S01\n", + "\n", + "退出服务:S03\n", + "\n", + "退出服务:S02\n", + "\n", + "退出服务\n" + ] + } + ], + "source": [ + "import queue\n", + "import threading\n", + "import time\n", + "\n", + "exitFlag = 0\n", + "\n", + "class BankServe(threading.Thread):\n", + " def __init__(self, threadID, name, q):\n", + " threading.Thread.__init__(self)\n", + " self.threadID = threadID\n", + " self.name = name\n", + " self.q = q\n", + " \n", + " def run(self):\n", + " print (\"开启服务:\" + self.name + '\\n')\n", + " process_data(self.name, self.q)\n", + " print (\"退出服务:\" + self.name + '\\n')\n", + "\n", + "def process_data(threadName, q):\n", + " while not exitFlag:\n", + " queueLock.acquire()\n", + " if not workQueue.empty():\n", + " data = q.get()\n", + " queueLock.release()\n", + " print('请{}号到{}号窗口!\\n'.format(data, threadName))\n", + " else:\n", + " queueLock.release()\n", + " time.sleep(1)\n", + "\n", + "serve_num = 3\n", + "custom_num = 5\n", + "queueLock = threading.Lock()\n", + "workQueue = queue.Queue(100)\n", + "threads = []\n", + "threadID = 1\n", + "\n", + "# 创建新线程\n", + "for i in range(serve_num):\n", + " thread = BankServe(threadID, 'S' + str(i+1).rjust(2, '0'), workQueue)\n", + " thread.start()\n", + " threads.append(thread)\n", + " threadID += 1\n", + "\n", + "# 填充队列\n", + "queueLock.acquire()\n", + "for i in range(custom_num):\n", + " print('Y' + str(i+1).rjust(4, '0'))\n", + " workQueue.put('Y' + str(i+1).rjust(4, '0'))\n", + "queueLock.release()\n", + "\n", + "# 等待队列清空\n", + "while not workQueue.empty():\n", + " pass\n", + "\n", + "# 通知线程是时候退出\n", + "exitFlag = 1\n", + "\n", + "# 等待所有线程完成\n", + "for t in threads:\n", + " t.join()\n", + "print (\"退出服务\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task05:字符串\n", + "**理论部分**\n", + "\n", + "用数组实现一个顺序的串结构。\n", + "为该串结构提供丰富的操作,比如插入子串、在指定位置移除给定长度的子串、在指定位置取子串、连接串、串匹配等。\n", + "练习部分\n", + "\n", + "**1.无重复字符的最长子串**\n", + "\n", + "https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/\n", + "\n", + "给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。\n", + "\n", + "示例1\n", + "```\n", + "输入: \"abcabcbb\"\n", + "输出: 3 \n", + "解释: 因为无重复字符的最长子串是 \"abc\",所以其长度为 3。\n", + "```\n", + "\n", + "示例2\n", + "```\n", + "输入: \"bbbbb\"\n", + "输出: 1\n", + "解释: 因为无重复字符的最长子串是 \"b\",所以其长度为 1。\n", + "```\n", + "\n", + "示例3\n", + "```\n", + "输入: \"pwwkew\"\n", + "输出: 3\n", + "解释: 因为无重复字符的最长子串是 \"wke\",所以其长度为 3。\n", + "请注意,你的答案必须是 子串 的长度,\"pwke\" 是一个子序列,不是子串。\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "abcabcbb 3\n", + "bbbbb 1\n", + "pwwkew 3\n" + ] + } + ], + "source": [ + "def lengthoflongestsubstring(s):\n", + " if not s:return 0\n", + " lookup = set()\n", + " maxlen = curlen = left = 0\n", + " for i in range(len(s)):\n", + " curlen += 1\n", + " while s[i] in lookup:\n", + " lookup.remove(s[left])\n", + " left += 1\n", + " curlen -= 1\n", + " maxlen = max(maxlen, curlen)\n", + " lookup.add(s[i])\n", + " return maxlen\n", + "\n", + "for s in ['abcabcbb','bbbbb','pwwkew']:\n", + " print(s, lengthoflongestsubstring(s))" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 9]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from itertools import permutations\n", + "\n", + "s = \"barfoothefoobarman\"\n", + "words = [\"foo\",\"bar\"]\n", + "res = []\n", + "for i in map(lambda x:''.join(x), set(permutations(words, len(words)))):\n", + " index = s.find(i)\n", + " if index != -1:\n", + " res.append(index)\n", + "res" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "QWER 0\n", + "QQWE 1\n", + "QQQW 2\n", + "QQQQ 3\n" + ] + } + ], + "source": [ + "from collections import defaultdict\n", + "def balancedString(s):\n", + " n = len(s)\n", + " if n <=0 or n%4 != 0:\n", + " return 0\n", + " m = n // 4\n", + " dic = defaultdict(int)\n", + " for c in s:\n", + " dic[c] += 1\n", + " if dic['Q']==m and dic['W']==m and dic['E']==m and dic['R']==m: #已经平衡了\n", + " return 0\n", + " min_window_len = n #窗口内为多了的 窗口外为ok的 没超阈值的\n", + " L = 0 #L R 均为实指\n", + " for R in range(n):\n", + " dic[s[R]] -= 1\n", + " while L <= R and dic['Q']<=m and dic['W']<=m and dic['E']<=m and dic['R']<=m:\n", + " min_window_len = min(min_window_len, R - L + 1)\n", + " dic[s[L]] += 1\n", + " L += 1\n", + " return min_window_len\n", + "\n", + "for s in ['QWER','QQWE','QQQW','QQQQ']:\n", + " print(s, balancedString(s))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/DataStructureAndAlgorithm/数据结构与算法(上).ipynb b/DataStructureAndAlgorithm/数据结构与算法(上).ipynb new file mode 100644 index 0000000..d8ed7e0 --- /dev/null +++ b/DataStructureAndAlgorithm/数据结构与算法(上).ipynb @@ -0,0 +1,838 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task01:数组(1天)\n", + "理论部分\n", + "\n", + "- 理解数组的存储与分类。\n", + "- 实现动态数组,该数组能够根据需要修改数组的长度。\n", + "\n", + "**1. 利用动态数组解决数据存放问题**\n", + "\n", + "编写一段代码,要求输入一个整数N,用动态数组A来存放2~N之间所有5或7的倍数,输出该数组。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5,7,10,14,15,20,21,25,28,30,35,40,42,45,49,50,55,56,60,63,65,70,75,77,80,84,85,90,91,95,98,100," + ] + } + ], + "source": [ + "def dynamiclist(N):\n", + " if N < 2:\n", + " return []\n", + " return filter(lambda x:x % 5 == 0 or x % 7 == 0, range(2,N+1))\n", + "\n", + "nums = dynamiclist(100)\n", + "for i in nums:\n", + " print(i, end = ',')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2. 托普利茨矩阵问题**\n", + "\n", + "https://leetcode-cn.com/problems/toeplitz-matrix/\n", + "\n", + "如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。\n", + "\n", + "给定一个M x N的矩阵,当且仅当它是托普利茨矩阵时返回True。" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "输入:\n", + "matrix = [\n", + " [1,2,3,4],\n", + " [5,1,2,3],\n", + " [9,5,1,2]\n", + "]\n", + "输出: True\n", + "解释:\n", + "在上述矩阵中, 其对角线为:\n", + "\"[9]\", \"[5, 5]\", \"[1, 1, 1]\", \"[2, 2, 2]\", \"[3, 3]\", \"[4]\"。\n", + "各条对角线上的所有元素均相同, 因此答案是`True`。\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "说明:\n", + "- matrix 是一个包含整数的二维数组。\n", + "- matrix 的行数和列数均在 [1, 20]范围内。\n", + "- matrix[i][j] 包含的整数在 [0, 99]范围内。\n", + "\n", + "进阶:\n", + "- 如果矩阵存储在磁盘上,并且磁盘内存是有限的,因此一次最多只能将一行矩阵加载到内存中,该怎么办?\n", + "- 如果矩阵太大以至于只能一次将部分行加载到内存中,该怎么办?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def toeplitz_mat(matrix):\n", + " if not matrix or not matrix[0]:\n", + " return False\n", + " for i in range(1, len(matrix)):\n", + " for j in range(1, len(matrix[0])):\n", + " if matrix[i][j] != matrix[i - 1][j - 1]:\n", + " return False\n", + " return True\n", + "\n", + "matrix = [[1,2,3,4],\n", + " [5,1,2,3],\n", + " [9,5,1,2]]\n", + "toeplitz_mat(matrix)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matrix = [[1,2],\n", + " [2,2]]\n", + "toeplitz_mat(matrix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3.三数之和**\n", + "\n", + "https://leetcode-cn.com/problems/3sum/\n", + "\n", + "给定一个包含 n 个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a + b + c = 0?找出所有满足条件且不重复的三元组。\n", + "\n", + "注意:答案中不可以包含重复的三元组。\n", + "\n", + "示例:\n", + "\n", + "```\n", + "给定数组 nums = [-1, 0, 1, 2, -1, -4],\n", + "\n", + "满足要求的三元组集合为:\n", + "[\n", + " [-1, 0, 1],\n", + " [-1, -1, 2]\n", + "]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[-1, -1, 2], [-1, 0, 1]]\n" + ] + } + ], + "source": [ + "def threesum(nums, target = 0):\n", + " if len(nums) < 3:\n", + " return []\n", + " nums.sort()\n", + " res = []\n", + " for i in range(len(nums) - 2):\n", + " if nums[i] > target:\n", + " return res\n", + " if i > 0 and nums[i] == nums[i - 1]:\n", + " continue\n", + " l, r = i + 1, len(nums) - 1\n", + " while l < r:\n", + " sum_ = nums[i] + nums[l] + nums[r]\n", + " if sum_ < target:\n", + " l += 1\n", + " elif sum_ > target:\n", + " r -= 1\n", + " else:\n", + " res.append([nums[i], nums[l], nums[r]])\n", + " while l < r and nums[l] == nums[l+1]:\n", + " l += 1\n", + " while l < r and nums[r] == nums[r-1]:\n", + " r -= 1\n", + " l += 1\n", + " r -= 1\n", + " return res\n", + " \n", + "nums = [-1, 0, 1, 2, -1, -4]\n", + "print(threesum(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task02:顺序表和链表\n", + "理论部分\n", + "\n", + "- 理解线性表的定义与操作。\n", + "- 实现顺序表。\n", + "- 实现单链表、循环链表、双向链表。\n", + "\n", + "**1.合并两个有序链表**\n", + "\n", + "https://leetcode-cn.com/problems/merge-two-sorted-lists/\n", + "\n", + "将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。\n", + "\n", + "示例:\n", + "\n", + "```\n", + "输入:1->2->4, 1->3->4\n", + "输出:1->1->2->3->4->4\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->1->2->3->4->4" + ] + } + ], + "source": [ + "# 链表定义\n", + "class ListNode:\n", + " def __init__(self, val, nextnode = None):\n", + " self.val = val\n", + " self.next = nextnode\n", + " \n", + "# 生成链表\n", + "def generate(nums):\n", + " head = cur = ListNode(-1)\n", + " for i in nums:\n", + " cur.next = cur = ListNode(i)\n", + " return head.next\n", + "\n", + "# 递归\n", + "def mergelist(head_1, head_2):\n", + " if not head_1:\n", + " return head_2\n", + " elif not head_2:\n", + " return head_1\n", + " elif head_1.val < head_2.val:\n", + " head_1.next = mergelist(head_1.next, head_2)\n", + " return head_1\n", + " else:\n", + " head_2.next = mergelist(head_1, head_2.next)\n", + " return head_2\n", + " \n", + "nums1, nums2 = [1,2,4], [1,3,4]\n", + "nums1, nums2 = generate(nums1), generate(nums2)\n", + "head = mergelist(nums1, nums2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->1->2->3->4->4" + ] + } + ], + "source": [ + "# 哑结点\n", + "def mergelist_1(head_1, head_2):\n", + " head = cur = ListNode(-1)\n", + " while head_1 and head_2:\n", + " if head_1.val < head_2.val:\n", + " cur.next, head_1 = head_1, head_1.next\n", + " else:\n", + " cur.next, head_2 = head_2, head_2.next\n", + " cur = cur.next\n", + " cur.next = head_1 if head_1 else head_2\n", + " return head.next\n", + "\n", + "nums1, nums2 = [1,2,4], [1,3,4]\n", + "nums1, nums2 = generate(nums1), generate(nums2)\n", + "head = mergelist_1(nums1, nums2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2. 删除链表的倒数第N个节点**\n", + "\n", + "https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/\n", + "\n", + "给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。\n", + "\n", + "示例:\n", + "```\n", + "给定一个链表: 1->2->3->4->5, 和 n = 2.\n", + "\n", + "当删除了倒数第二个节点后,链表变为 1->2->3->5.\n", + "说明:给定的 n 保证是有效的。\n", + "\n", + "进阶:你能尝试使用一趟扫描实现吗?\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->3->4" + ] + } + ], + "source": [ + "# 2次扫描\n", + "def deletenode(head, n):\n", + " cur, ans = head, 0\n", + " while cur:\n", + " ans += 1\n", + " cur = cur.next\n", + " dummy = cur = ListNode(-1, head)\n", + " for i in range(ans - n):\n", + " cur = cur.next\n", + " cur.next = cur.next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1, 6))\n", + "head = deletenode(nums, 1)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->4->5" + ] + } + ], + "source": [ + "# 1次扫描 空间换时间\n", + "def deletenode_1(head, n):\n", + " hash_map = {}\n", + " cur = dummy = ListNode(-1, head)\n", + " ans = 0\n", + " while cur:\n", + " ans += 1\n", + " hash_map[ans] = cur\n", + " cur = cur.next\n", + " # 被删除的节点索引\n", + " index = ans - n\n", + " hash_map[index].next = hash_map[index].next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1,6))\n", + "head = deletenode_1(nums, 3)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1->2->3->5" + ] + } + ], + "source": [ + "# 栈实现\n", + "def deletenode_2(head, n):\n", + " dummy = cur = ListNode(-1, head)\n", + " stack = []\n", + " while cur:\n", + " stack.append(cur)\n", + " cur = cur.next\n", + " for i in range(n):\n", + " stack.pop()\n", + " prev = stack[-1]\n", + " prev.next = prev.next.next\n", + " return dummy.next\n", + "\n", + "nums = generate(range(1,6))\n", + "head = deletenode_2(nums, 2)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3. 旋转链表**\n", + "\n", + "https://leetcode-cn.com/problems/rotate-list/\n", + "\n", + "给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。\n", + "\n", + "示例 1:\n", + "```\n", + "输入: 1->2->3->4->5->NULL, k = 2\n", + "输出: 4->5->1->2->3->NULL\n", + "\n", + "解释:\n", + "向右旋转 1 步: 5->1->2->3->4->NULL\n", + "向右旋转 2 步: 4->5->1->2->3->NULL\n", + "```\n", + "\n", + "示例2:\n", + "```\n", + "输入: 0->1->2->NULL, k = 4\n", + "输出: 2->0->1->NULL\n", + "\n", + "解释:\n", + "向右旋转 1 步: 2->0->1->NULL\n", + "向右旋转 2 步: 1->2->0->NULL\n", + "向右旋转 3 步: 0->1->2->NULL\n", + "向右旋转 4 步: 2->0->1->NULL\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4->5->1->2->3" + ] + } + ], + "source": [ + "# 首先建立循环链表\n", + "def rotate(head, k):\n", + " cur, n = head, 1\n", + " while cur.next:\n", + " cur = cur.next\n", + " n += 1\n", + " cur.next = head\n", + " \n", + " new_tail = head\n", + " for i in range(n - k%n - 1):\n", + " new_tail = new_tail.next\n", + " new_head = new_tail.next\n", + " new_tail.next = None\n", + " return new_head\n", + "\n", + "nums, k = generate(range(1,6)), 2\n", + "head = rotate(nums, k)\n", + "while head:\n", + " print(head.val, end = '->' if head.next else '')\n", + " head = head.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task03:栈与递归\n", + "**理论部分**\n", + "\n", + "- 用数组实现一个顺序栈。\n", + "- 用链表实现一个链栈。\n", + "- 理解递归的原理。\n", + "\n", + "**1. 根据要求完成车辆重排的程序代码**\n", + "\n", + "假设一列货运列车共有n节车厢,每节车厢将停放在不同的车站。假定n个车站的编号分别为1至n,货运列车按照第n站至第1站的次序经过这些车站。车厢的编号与它们的目的地相同。为了便于从列车上卸掉相应的车厢,必须重新排列车厢,使各车厢从前至后按编号1至n的次序排列。当所有的车厢都按照这种次序排列时,在每个车站只需卸掉最后一节车厢即可。\n", + "\n", + "我们在一个转轨站里完成车厢的重排工作,在转轨站中有一个入轨、一个出轨和k个缓冲铁轨(位于入轨和出轨之间)。图(a)给出一个转轨站,其中有k个(k=3)缓冲铁轨H1,H2 和H3。开始时,n节车厢的货车从入轨处进入转轨站,转轨结束时各车厢从右到左按照编号1至n的次序离开转轨站(通过出轨处)。在图(a)中,n=9,车厢从后至前的初始次序为5,8,1,7,4,2,9,6,3。图(b)给出了按所要求的次序重新排列后的结果。" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task04:队列\n", + "**理论部分**\n", + "\n", + "- 用数组实现一个顺序队列。\n", + "- 用数组实现一个循环队列。\n", + "- 用链表实现一个链式队列。\n", + "\n", + "**1. 模拟银行服务完成程序代码。**\n", + "\n", + "目前,在以银行营业大厅为代表的窗口行业中大量使用排队(叫号)系统,该系统完全模拟了人群排队全过程,通过取票进队、排队等待、叫号服务等功能,代替了人们站队的辛苦。\n", + "\n", + "排队叫号软件的具体操作流程为:\n", + "\n", + "- 顾客取服务序号\n", + "\n", + "当顾客抵达服务大厅时,前往放置在入口处旁的取号机,并按一下其上的相应服务按钮,取号机会自动打印出一张服务单。单上显示服务号及该服务号前面正在等待服务的人数。\n", + "\n", + "- 服务员工呼叫顾客\n", + "\n", + "服务员工只需按一下其柜台上呼叫器的相应按钮,则顾客的服务号就会按顺序的显示在显示屏上,并发出“叮咚”和相关语音信息,提示顾客前往该窗口办事。当一位顾客办事完毕后,柜台服务员工只需按呼叫器相应键,即可自动呼叫下一位顾客。\n", + "\n", + "编写程序模拟上面的工作过程,主要要求如下:\n", + "\n", + "- 程序运行后,当看到“请点击触摸屏获取号码:”的提示时,只要按回车键,即可显示“您的号码是:XXX,您前面有YYY位”的提示,其中XXX是所获得的服务号码,YYY是在XXX之前来到的正在等待服务的人数。\n", + "- 用多线程技术模拟服务窗口(可模拟多个),具有服务员呼叫顾客的行为,假设每个顾客服务的时间是10000ms,时间到后,显示“请XXX号到ZZZ号窗口!”的提示。其中ZZZ是即将为客户服务的窗口号。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开启服务:S01\n", + "\n", + "开启服务:S02\n", + "\n", + "开启服务:S03\n", + "Y0001\n", + "Y0002\n", + "Y0003\n", + "Y0004\n", + "Y0005\n", + "\n", + "请Y0001号到S03号窗口!\n", + "\n", + "请Y0002号到S02号窗口!\n", + "\n", + "请Y0003号到S01号窗口!\n", + "\n", + "请Y0004号到S03号窗口!\n", + "\n", + "请Y0005号到S02号窗口!\n", + "\n", + "退出服务:S01\n", + "\n", + "退出服务:S03\n", + "\n", + "退出服务:S02\n", + "\n", + "退出服务\n" + ] + } + ], + "source": [ + "import queue\n", + "import threading\n", + "import time\n", + "\n", + "exitFlag = 0\n", + "\n", + "class BankServe(threading.Thread):\n", + " def __init__(self, threadID, name, q):\n", + " threading.Thread.__init__(self)\n", + " self.threadID = threadID\n", + " self.name = name\n", + " self.q = q\n", + " \n", + " def run(self):\n", + " print (\"开启服务:\" + self.name + '\\n')\n", + " process_data(self.name, self.q)\n", + " print (\"退出服务:\" + self.name + '\\n')\n", + "\n", + "def process_data(threadName, q):\n", + " while not exitFlag:\n", + " queueLock.acquire()\n", + " if not workQueue.empty():\n", + " data = q.get()\n", + " queueLock.release()\n", + " print('请{}号到{}号窗口!\\n'.format(data, threadName))\n", + " else:\n", + " queueLock.release()\n", + " time.sleep(1)\n", + "\n", + "serve_num = 3\n", + "custom_num = 5\n", + "queueLock = threading.Lock()\n", + "workQueue = queue.Queue(100)\n", + "threads = []\n", + "threadID = 1\n", + "\n", + "# 创建新线程\n", + "for i in range(serve_num):\n", + " thread = BankServe(threadID, 'S' + str(i+1).rjust(2, '0'), workQueue)\n", + " thread.start()\n", + " threads.append(thread)\n", + " threadID += 1\n", + "\n", + "# 填充队列\n", + "queueLock.acquire()\n", + "for i in range(custom_num):\n", + " print('Y' + str(i+1).rjust(4, '0'))\n", + " workQueue.put('Y' + str(i+1).rjust(4, '0'))\n", + "queueLock.release()\n", + "\n", + "# 等待队列清空\n", + "while not workQueue.empty():\n", + " pass\n", + "\n", + "# 通知线程是时候退出\n", + "exitFlag = 1\n", + "\n", + "# 等待所有线程完成\n", + "for t in threads:\n", + " t.join()\n", + "print (\"退出服务\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task05:字符串\n", + "**理论部分**\n", + "\n", + "用数组实现一个顺序的串结构。\n", + "为该串结构提供丰富的操作,比如插入子串、在指定位置移除给定长度的子串、在指定位置取子串、连接串、串匹配等。\n", + "练习部分\n", + "\n", + "**1.无重复字符的最长子串**\n", + "\n", + "https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/\n", + "\n", + "给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。\n", + "\n", + "示例1\n", + "```\n", + "输入: \"abcabcbb\"\n", + "输出: 3 \n", + "解释: 因为无重复字符的最长子串是 \"abc\",所以其长度为 3。\n", + "```\n", + "\n", + "示例2\n", + "```\n", + "输入: \"bbbbb\"\n", + "输出: 1\n", + "解释: 因为无重复字符的最长子串是 \"b\",所以其长度为 1。\n", + "```\n", + "\n", + "示例3\n", + "```\n", + "输入: \"pwwkew\"\n", + "输出: 3\n", + "解释: 因为无重复字符的最长子串是 \"wke\",所以其长度为 3。\n", + "请注意,你的答案必须是 子串 的长度,\"pwke\" 是一个子序列,不是子串。\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "abcabcbb 3\n", + "bbbbb 1\n", + "pwwkew 3\n" + ] + } + ], + "source": [ + "def lengthoflongestsubstring(s):\n", + " if not s:return 0\n", + " lookup = set()\n", + " maxlen = curlen = left = 0\n", + " for i in range(len(s)):\n", + " curlen += 1\n", + " while s[i] in lookup:\n", + " lookup.remove(s[left])\n", + " left += 1\n", + " curlen -= 1\n", + " maxlen = max(maxlen, curlen)\n", + " lookup.add(s[i])\n", + " return maxlen\n", + "\n", + "for s in ['abcabcbb','bbbbb','pwwkew']:\n", + " print(s, lengthoflongestsubstring(s))" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 9]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from itertools import permutations\n", + "\n", + "s = \"barfoothefoobarman\"\n", + "words = [\"foo\",\"bar\"]\n", + "res = []\n", + "for i in map(lambda x:''.join(x), set(permutations(words, len(words)))):\n", + " index = s.find(i)\n", + " if index != -1:\n", + " res.append(index)\n", + "res" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "QWER 0\n", + "QQWE 1\n", + "QQQW 2\n", + "QQQQ 3\n" + ] + } + ], + "source": [ + "from collections import defaultdict\n", + "def balancedString(s):\n", + " n = len(s)\n", + " if n <=0 or n%4 != 0:\n", + " return 0\n", + " m = n // 4\n", + " dic = defaultdict(int)\n", + " for c in s:\n", + " dic[c] += 1\n", + " if dic['Q']==m and dic['W']==m and dic['E']==m and dic['R']==m: #已经平衡了\n", + " return 0\n", + " min_window_len = n #窗口内为多了的 窗口外为ok的 没超阈值的\n", + " L = 0 #L R 均为实指\n", + " for R in range(n):\n", + " dic[s[R]] -= 1\n", + " while L <= R and dic['Q']<=m and dic['W']<=m and dic['E']<=m and dic['R']<=m:\n", + " min_window_len = min(min_window_len, R - L + 1)\n", + " dic[s[L]] += 1\n", + " L += 1\n", + " return min_window_len\n", + "\n", + "for s in ['QWER','QQWE','QQQW','QQQQ']:\n", + " print(s, balancedString(s))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}