首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Python高级知识点学习(一)

image.png Python中一切皆对象 和Java相比,Python的面向对象更加彻底。 函数和类也是对象,是python的一等公民。 代码和模块也可以称之为对象。 python中的类也是对象,类可以理解为模板,根据这个模板去生成我们的对象,可以动态修改类的属性。 何为一等公民? 可以赋值给一个变量 可以添加到集合对象中 可以作为参数传递给函数 可以当做函数的返回值 (生成器应用) type、object、class之间的关系 类是由type来生成的一个对象,object是所有类都要继承的最顶层的一个基础类,type也是一个类,同时也是一个对象。 看代码片段一: a = 1 b = "abc" print(type(1)) print(type(int)) print(type(b)) print(type(str)) 打印出的结果: <class 'int'> <class 'type'> <class 'str'> <class 'type'> 代码片段二: class Student: pass class MyStudent(Student): pass stu = Student() print(type(stu)) print(type(Student)) print(int.__bases__) print(str.__bases__) print(Student.__bases__)# 打印Student基类 print(MyStudent.__bases__)# 打印Student基类 print(type.__bases__) print(object.__bases__) # 最顶层的类的基类为空 print(type(object)) 打印出的结果: <class '__main__.Student'> <class 'type'> (<class 'object'>,) (<class 'object'>,) (<class 'object'>,) (<class '__main__.Student'>,) (<class 'object'>,) () <class 'type'> 可以看到,类是由type来生成的一个对象。 上述代码建议反复阅读练习。 Python中常见的内置类型 首先说明对象的三个特征: 身份:也就是地址,通过id()函数查看地址 类型:int、str等 值:每个对象都有自己的值 常见内置类型: None(全局只有一个),Python解释器在启动时会用None生成一个None对象。 a = None b = None print(id(a) == id(b)) 打印结果: Ture 可以看到a,b是指向同一个对象(id相同)。 数值类型:int float complex(复数) bool。 迭代类型:可用for进行遍历 序列类型:list、bytes、range、tuple、str、array 等 映射类型:dict 集合类型:set、frozenset 上下文管理器:with语句 其他:class、实例 等等等。 Python中的魔法函数 问:什么是魔法函数? 答:双下划线开头,双下划线结尾的这些函数,通常称之为魔法函数。 例如: image.png 一般魔法函数不要自定义,使用 Python 提供的即可。 使用 Python 提供的魔法函数,为了增强类的特性。 代码:使用魔法函数之前 class Company(object): def __init__(self, employee_list): self.employee = employee_list company = Company(["tom", "bob", "jane"]) for i in company.employee: print(i) 打印结果: a b c 代码:使用魔法函数之后 class Company(object): def __init__(self, employee_list): self.employee = employee_list def __getitem__(self, item): return self.employee[item] company = Company(["a", "b", "c"]) 打印结果: a b c 可以看到__getitem__()这个魔法函数的功能。 定义了这个魔法函数后,实例化后的对象就隐含的变为可迭代对象(iterable)。 for循环其实是要拿到一个对象的迭代器,迭代器是需要实现__iter__这个方法才会有迭代器特性,Python语法会做一些优化,如果拿不到迭代器,就会尝试去对象中找__getitem__这个方法,如果有的话就会调用这个方法,一次一次直到将数据取完。这是python语言本身解释器会完成的功能。 魔法函数调用不需要显示调用,解释器会隐式调用。 Python的数据模型 魔法函数是Python数据模型的一个概念而已,因为网络上大家喜欢称之为魔法函数。 Python数据模型会增强对象的特性。 class Company(object): def __init__(self, employee_list): self.employee = employee_list def __getitem__(self, item): return self.employee[item] def __len__(self): return len(self.employee) company = Company(["a", "b", "c"]) print(len(company)) 结果: 3 __len__魔法函数增强了company对象的特性。 因为魔法函数很多,类似的魔法函数请大家自行去网上查找,并查看用法。

优秀的个人博客,低调大师

14.Swift学习之闭包

闭包引入 计算1个数的平方 函数写法 func square(param:Int) -> Int{ return param * param } square(param:3) 闭包写法 let squareCloure = { (param:Int) -> Int in return param * param } squareCloure(3) 闭包含义 闭包是可以被传递和引用的一个独立模块 闭包能够捕获和存储定义在其上下文中的任何常量和变量,即闭合并包裹那些常量和变量,因此被称为“闭包” 闭包符合如下三种形式中的一种: 全局函数是一个有名字但不会捕获任何值的闭包 内嵌函数是一个有名字且能从其上层函数捕获值的闭包(函数中的嵌套函数知识点) 闭包表达式是一个轻量级语法,可以捕获其上下文中常量或变量值的没有名字的闭包 闭包和函数一样也是引用类型 简单案例 案例一 let demo= { print("Swift 闭包实例。") } demo() 案例二 let divide = {(val1: Int, val2: Int) -> Int in return val1 / val2 } let result = divide(200, 20) print (result) 闭包表达式 闭包表达式语法有如下的一般形式: { (parameters) -> (return type) in statements } 闭包表达式由一对{}开始与结束 由in关键字将闭包分割成两部分:参数与返回值、闭包体 闭包参数与函数参数的区别 形式参数不能提供默认值,其他和函数一样 闭包主要知识点 参数名称缩写 Swift 提供了参数名称的缩写功能,直接通过 $0,$1,$2来顺序调用闭包的参数 在闭包表达式中使用参数名称缩写,可以在闭包参数列表中省略对其定义 参数类型可以通过函数类型进行推断 在单行闭包的时候,return 关键字可以省略 参数名称省略以后,in 关键字也可以被省略 //从数组中筛选指出合适的数据组成新的数组 func getList(score:[Int], con:(Int)->Bool) -> [Int]{ var newScore:[Int] = [Int]() for item in score { if con(item) { newScore.append(item) } } return newScore } let newAarray = getList(score: [75,60,95,45,85], con:{(s:Int)->Bool in return s>80}) print(newAarray) 第一种简写: 省略 ->与返回类型(根据后面表达式可以推断返回值是一个Bool) let newAarray = getList(score: [75,60,95,45,85], con:{(s:Int) in return s>80}) 第二种简写:省略参数类型和括号(根据函数的参数可推断传进来的必然是Int) let newAarray = getList(score: [75,60,95,45,85], con:{s in return s>80}) 第三种简写:省略return关键字 let newAarray = getList(score: [75,60,95,45,85], con:{s in s>80}) 第四种简写:参数名称缩写,省略参数声明和in,改为$0 let newAarray = getList(score: [75,60,95,45,85], con:{$0>80}) 捕获 闭包可以从上下文环境中捕获常量、变量,并在自己的作用域内使用 Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数,嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。 func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { runningTotal += amount return runningTotal } return incrementor } let incrementByTen = makeIncrementor(forIncrement: 10) // 返回的值为10 print(incrementByTen()) // 返回的值为20 print(incrementByTen()) // 返回的值为30 print(incrementByTen()) 尾随闭包 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用 闭包是函数的最后一个参数 调用时,函数的 ) 可以前置到倒数第二个参数末尾,后面的参数直接使用 { // 执行代码 },形式参数标签也随之省略 将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性 //尾随闭包 func doSomething(info:String, clousre:(String)->Void){ clousre(info) } //不使用尾随闭包进行函数调用 doSomething(info: "Hello", clousre: { s in print(s) }) //使用尾随闭包进行函数调用 doSomething(info: "World") { s in print(s) } 逃逸闭包 闭包作为一个参数传递给一个函数 传入函数的闭包如果在函数执行结束之后才会被调用,那么这个闭包就叫做逃逸闭包 声明一个接受闭包作为形式参数的函数时,可以在形式参数的类型之前写上@escaping 来明确闭包是允许逃逸的 逃逸闭包会在函数结束后才执行 举例 //逃逸闭包:闭包可以超出函数的范围来调用 //存放没有参数、没有返回值的闭包 var closureArray :[()->Void] = [()->Void]() //定义一个函数,接收一个非逃逸闭包为参数 func nonEscapeClosure(closure:()->Void){ closure() } //定义一个函数,接收一个逃逸闭包为参数,将闭包并存储到一个数组里面去,并没有调用 func escapeClosure(closure: @escaping ()->Void){ print("函数开始") closureArray.append(closure) print("函数结束") } var x = 10 //打印10 print(x) nonEscapeClosure { x = 100 } //打印100 因为闭包在函数里面执行了 print(x) escapeClosure { x = 200 } //打印100 因为闭包逃逸了 没有在函数里面执行 print(x) closureArray.first?() //打印200 在函数外面调用了闭包 print(x) //尾随闭包常用于异步回调 自动闭包 一种自动创建的闭包,用于包装函数参数的表达式 不接受任何参数,被调用时会返回被包装在其中的表达式的值 在形式参数的类型之前加上@autoclosure关键字标识这是一个逃逸闭包 //自动闭包 func printIfTrue(predicate:@autoclosure ()->Bool){ if predicate() { print("is true") } else{ print("is false") } } //直接进行调用了,Swift 将会把 2 > 1 这个表达式自动转换为 () -> Bool。这样我们就得到了一个写法简单、表意清楚的表达式。 printIfTrue(predicate: 2>1) printIfTrue(predicate: 2<1) 闭包的循环引用 class NetworkTools: NSObject { /// 完成回调属性 var finishedCallBack: (()->())? /// 加载数据 /// - parameter finished: 完成回调 func loadData(finished: () -> ()) { self.finishedCallBack = finished working() } func working() { finishedCallBack?() } deinit { print("网络工具 88") } class ViewController: UIViewController { var tools: NetworkTools? override func viewDidLoad() { super.viewDidLoad() tools = NetworkTools() tools?.loadData() { print("加载数据完成,更新界面:", NSThread.currentThread()) weakSelf!.view.backgroundColor = UIColor.redColor() } } /// 与 OC 中的 dealloc 类似,注意此函数没有() deinit { print("控制器 88") } } Swift中解决循环引用的方式 方案一: 使用weak,对当前控制器使用弱引用 但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数) // 解决方案一: weak var weakSelf = self tools.loadData { print("加载数据完成,更新界面:", NSThread.currentThread()) weakSelf!.view.backgroundColor = UIColor.redColor() } 方案二: 和方案一类型,只是书写方式更加简单 可以写在闭包中,并且在闭包中用到的self都是弱引用 tools.loadData {[weak self] () -> () in print("加载数据完成,更新界面:", NSThread.currentThread()) self!.view.backgroundColor = UIColor.redColor() } 方案三: 使用关键字unowned 从行为上来说 unowned 更像OC中的 unsafe_unretained unowned 表示:即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil tools.loadData {[unowned self] () -> () in print("加载数据完成,更新界面:", NSThread.currentThread()) self.view.backgroundColor = UIColor.redColor() }

优秀的个人博客,低调大师

leetcode算法题学习Java版(2)

283.Move Zeros(移动零) 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次数。 class Solution { public void moveZeroes(int[] nums) { int k = 0; for(int i = 0;i<nums.length;i++){ if(nums[i]!=0){ if(i!=k){ int temp = nums[k]; nums[k] = nums[i]; nums[i] = temp; } k++; } } } } 75.Sort Colors(颜色分类) 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 注意: 不能使用代码库中的排序函数来解决这道题。 示例:输入: [2,0,2,1,1,0]输出: [0,0,1,1,2,2]进阶: 一个直观的解决方案是使用计数排序的两趟扫描算法。 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 你能想出一个仅使用常数空间的一趟扫描算法吗? 解题思路,本题共三个元素,非常适合三路快排的方法,并且仅需扫描数组一遍即可完成排序 class Solution { public void sortColors(int[] nums) { int zero = -1; // nums[0...zero]==0 int two = nums.length; //nums[two...n-1]==2 for (int i = 0; i < two;) { if(nums[i]==0){ int temp = nums[++zero]; nums[zero] = nums[i]; nums[i++] = temp; }else if(nums[i]==1){ i++; }else{ assert nums[i]==2; int temp = nums[--two]; nums[two] = nums[i]; nums[i] = temp; } } } } 88.Merged sorted Array(合并有序数组) 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 说明: 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 示例: 输入: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3 输出: [1,2,2,3,5,6] 解题思路:这道题解决很简单,但是最大效率的算法却也比较难想,很巧妙,暴力解法就是把两个数组合并,然后快排。但是参照了leetcode上别人的代码,效率更高,思路就是不断比较二者的最大值,把最大值放在nums1数组的最后,知道排序成功。 class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { int count = m + n - 1; m--; n--; while (m != -1 && n != -1) { nums1[count--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; } while (n != -1) { nums1[count--] = nums2[n--]; } } } 215.Kth Largest Element in an Array(数组中第K个最大的元素) 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 这道题很有趣,他的解法非常多,我也是在这道题感受到了自己与大佬之间的差距,就算用同一种解法,别人的代码也比我写的优雅的多。令人哭笑不得的是,自己写了半天的算法,其实运行下来比别人两行代码(Array.sort,调用jdk内置的函数)就搞定了还慢了很多倍。 解题思路:这道题用简单暴力的解法是非常容易的,同样是先对数组进行排序,最简单的办法是用jdk内置的Array.sort进行排序,然后从后往前取第k个元素,这种解法既简单,又由于jdk内置的快排效率非常高,在leetcode上这种解法只用了4ms,排名第二。当然更聪明的解法很多,例如,使用快排(分治算法),在快排的每一趟排完后,如果要找的k较大,则只对对应的一半继续进行快排,直到找到结果。还有使用堆的办法。 class Solution { public int findKthLargest(int[] nums, int k) { Queue<Integer> queue = new PriorityQueue<Integer>(); for (int i = 0; i < nums.length; i++) { if (i < k) { queue.add(nums[i]); } else if (queue.peek() < nums[i]) { queue.remove(); queue.add(nums[i]); } } return queue.peek(); } } class Solution { public int findKthLargest(int[] nums, int k) { int left = 0, right = nums.length - 1; while (true){ int pos = partition(nums, left, right); if(k - 1 == pos) return nums[pos]; else if(pos > k - 1) right = pos - 1; else left = pos + 1; } } public int partition(int[] nums, int left, int right){ int pivot = nums[left], l = left +1, r = right; while (l <= r){ if(nums[l] < pivot && nums[r] > pivot) swap(nums, l, r); if (nums[r] <= pivot) r--; if (nums[l] >= pivot) l++; } swap(nums, left, r); return r; } public void swap(int nums[], int left, int right){ int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; } } Two Sum II(两数之和) 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 说明: 返回的下标值(index1 和 index2)不是从零开始的。 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 示例: 输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 解题思路:这道题同样有多种思路,暴力解法是两次遍历该数组,找到相加等于target的索引,这种解法的时间复杂度是O(n^2)。利用二分法的思想来解这道题,时间复杂度是O(nlogn)。而利用对撞指针来解这道题,时间复杂度只有O(n),以下是对撞指针的解法。 class Solution { public int[] twoSum(int[] numbers, int target) { int i = 0,j = numbers.length-1; while(i<j){ if(numbers[i]+numbers[j]==target){ break; } if(numbers[i]+numbers[j]>target){ j--; } if(numbers[i]+numbers[j]<target){ i++; } } return new int[]{++i,++j}; } } 209.Minimum Size Subarray Sum(最小子数组) 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 示例: 输入: s = 7, nums = [2,3,1,2,4,3] 输出: 2 解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。 进阶: 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。 解题思路:该题使用滑动窗口法解决只需要O(n)的时间复杂度 public class MSSubarraySum { public int minSubArrayLen(int s, int[] nums) { int i = 0, j = -1; int sum = 0; int result = nums.length+1; while(i<nums.length){ if(j<nums.length-1&&sum<s){ sum+=nums[++j]; }else{ sum-=nums[i++]; } if(sum>=s) result = Math.min(result,j-i+1); } if(result == nums.length+1){ result = 0; } return result; } } 3.Longest Substring Without Repeating Characters(无重复字符的最小子串) 给定一个字符串,找出不含有重复字符的最长子串的长度。 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 3。 示例 2: 输入: "bbbbb" 输出: 1 解释: 无重复字符的最长子串是 "b",其长度为 1。 示例 3: 输入: "pwwkew" 输出: 3 解释: 无重复字符的最长子串是 "wke",其长度为 3。 请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。 解题思路:这道题同样是使用滑动窗口的思想去解是最佳的。该题需要记录每个字符出现的频率,因此初始化一个长度为256的freq数组,根据字符的ASCII码来每个字符出现的频率。根据频率来进行窗口的滑动。 class Solution { public int lengthOfLongestSubstring(String s) { int[] freq = new int[256]; for (int f = 0; f < freq.length; f++) { freq[f] = 0; } int i = 0, j = -1; int result = 0; while (i < s.length()) { if (j < s.length() - 1 && freq[s.charAt(j + 1)] == 0) { freq[s.charAt(++j)]++; }else{ freq[s.charAt(i++)]--; } result = Math.max(result, j - i + 1); } return result; } } Minimum Window Substring(最小覆盖子串) 给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。 示例: 输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC" 说明: 如果 S 中不存这样的子串,则返回空字符串 ""。 如果 S 中存在这样的子串,我们保证它是唯一的答案。 解题思路:这道题我依然是使用滑动窗口的思想去解的,时间复杂度为O(2st),解题耗时较长,主要原因是每次都要遍历一遍结果集去判断结果是否正确,可以去参考leetcode 该题更好的解法。 class Solution { public String minWindow(String s, String t) { HashMap<Integer,Integer> target = new HashMap<>(); for(int i =0;i<t.length();i++){ if(target.get((int)t.charAt(i))==null){ target.put((int) t.charAt(i),1); }else{ int temp = target.get((int)t.charAt(i)); target.put((int) t.charAt(i),temp+1); } } int freq[] = new int[256]; for (int i = 0; i < freq.length; i++) freq[i] = 0; int i = 0, j = -1; int length = Integer.MAX_VALUE; String result = ""; while(i<s.length()){ if(j<s.length()-1&&!hasFound(freq,target)){ freq[s.charAt(++j)]++; }else{ freq[s.charAt(i++)]--; } if(hasFound(freq,target)){ if(length>j-i+1){ length = j-i+1; result = s.substring(i,j+1); } } } return result; } public static boolean hasFound(int[] arr1,HashMap<Integer,Integer> arr2){ // for(int i =0;i<arr2.length;i++){ // if(arr1[arr2[i]]<1) // return false; // } Iterator iter = arr2.entrySet().iterator(); while(iter.hasNext()){ Map.Entry<Integer,Integer> entry = (Map.Entry) iter.next(); if(arr1[entry.getKey()]<entry.getValue()){ return false; } } return true; } } 451.Sort Characters By Frequency(根据字符出现频率排序) 示例 1: 输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。 因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。 解题思路:这里我是用HashMap来解的,不过最后用了比较笨的办法来按顺序拼凑字符串。是通过类似选择排序的办法,每次比较map里的所有value值,将最大的值拿出来放在最前面。Leetcode上有更好的方法可以借鉴。 class Solution { public String frequencySort(String s) { Map<Character,Integer> map = new HashMap<>(); for(int i =0;i<s.length();i++){ map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1); } StringBuffer result = new StringBuffer(); int temp = -1; char tempKey=' '; int i = 0; while(i<s.length()){ for (Map.Entry<Character,Integer> entry:map.entrySet()) { if(temp<entry.getValue()){ tempKey = entry.getKey(); temp = entry.getValue(); } } map.remove(tempKey); while(temp>0){ result.append(tempKey); i++; temp--; } } return result.toString(); } } 15.3Sum(三数之和) 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 注意:答案中不可以包含重复的三元组。 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] 解题思路:我用的是对撞指针的方式,遍历数组的过程中,对当前遍历的索引之后的数,采用对撞指针的方式,找到和等于0-nums【i】的两个数。我的代码略有瑕疵导致速度较慢,以下为leetcode上解题思路与我相同,但是做了细节优化的代码 class Solution { public List<List<Integer>> threeSum(int[] nums) { int len=nums.length; Arrays.sort(nums); List<List<Integer>> res = new ArrayList<>(); for(int i=0;i<len;i++){ if(nums[i]>0)break; //简化,如果>0则说明该三数之和不可能为0 if(i>0&&nums[i]==nums[i-1])continue; //去重 int target=0-nums[i]; int l=i+1,r=len-1; //此处必须对i后面的数字进行筛选,不能重复 while(l<r){ List<Integer> list=new ArrayList(); if(nums[l]+nums[r]==target){ list.add(nums[i]); list.add(nums[l]); list.add(nums[r]); res.add(list); while(r>l&&nums[l+1]==nums[l])l++; //这个地方改成l-1只会出现一个结果了 while(r>l&&nums[r]==nums[r-1])r--; l++;r--; }else if(nums[l]+nums[r]>target)r--; else l++; } } return res; } } 454.4SumII(四数相加II) 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。 例如: 输入: A = [ 1, 2] B = [-2,-1] C = [-1, 2] D = [ 0, 2] 输出: 2 解释: 两个元组如下: (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 解题思路:暴力解法为遍历四个数组所有情况,时间复杂度为O(n^4 )。本题我使用了查找表的方法,将数组A和B的所有和的情况置入查找表中,遍历C和数组D即可得到结果,时间复杂度为O(n^2) public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { int result = 0; Map<Integer,Integer> map = new HashMap<>(); for(int i = 0;i<A.length;i++){ for(int j = 0;j<B.length;j++){ map.put(A[i]+B[j],map.getOrDefault(A[i]+B[j],0)+1); } } for(int i = 0;i<C.length;i++){ for(int j = 0;j<D.length;j++){ if(map.containsKey(0-C[i]-D[j])){ result+=map.get(0-C[i]-D[j]); } } } return result; } 206. Reverse Linked List 反转链表 反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶: 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 解题思路:对于链表题来说,一般不能直接操作链表节点的值,而是通过操作指针来改变链表。例如,扫描一遍链表,将值压入栈中,再第二次扫描链表,将值从栈中弹出,这种方式一般在面试的算法题中是不被允许的。因此,这道题我用了三个临时指针,只改变listNode的next指针的方向来改变链表。 public class ReverseLinkedList { public ListNode reverseList(ListNode head) { if(head == null) return head; ListNode pre = null, cur = head, next = head.next; while (cur != null){ cur.next = pre; pre = cur; cur = next; if(next!=null){ next = next.next; } } return pre; } } 92. Reverse Linked List II 反转链表 II 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 说明: 1 ≤ m ≤ n ≤ 链表长度。 示例: 输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL 这道题个人感觉还是挺难的,因为要处理的特殊情况较多,又不能直接更改节点的值,而是要通过指针来实现反转链表。这里还是以leetcode上大神写的更优美的代码为例吧 public ListNode reverseBetween_1(ListNode head, int m, int n) { if (head == null || m < 1 || m > n) return null; ListNode head1 = head; ListNode preTail = null;//需要逆置节点的前驱节点 //第一步:前进至第m节点,即行走m-1步;注意考虑m为1的情况,此时preTail=null int i = 1; while(head1 != null && i++ < m){ preTail = head1; head1 = head1.next; } //第二步:反转m->n节点 if(head1 == null) return head;//head1为null,不需要后翻转了 ListNode preNode = null; ListNode reverseListPreHead = head1; ListNode nextNode; while (head1 != null && m++ <= n) { nextNode = head1.next; head1.next = preNode; preNode = head1; head1 = nextNode; } //第三步:反转链表的头尾处理 reverseListPreHead.next = head1;//处理尾巴 if (preTail != null) {//处理头部 preTail.next = preNode; return head; }else{ return preNode;//若preTail为null,返回翻转链表段的最后一个节点 } } Remove Duplicates from Sorted List 删除排序链表中的重复元素 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 示例 1: 输入: 1->1->2 输出: 1->2 示例 2: 输入: 1->1->2->3->3 输出: 1->2->3 解题思路:这道题题意我理解错了,不知道是不是题目表达的问题,让我误以为要删除所有的不管是否相邻的具有重复值的节点。但看了leetcode上其他人的代码,都只是删除相邻的重复的节点。 if(head ==null) return null; if(head.next == null) return head; Set<Integer> set = new HashSet<>(); ListNode temp = new ListNode(-1); temp.next = head; while (temp!=null&&temp.next!=null){ ListNode next = temp.next; if(set.contains(next.val)) temp.next = temp.next.next; else{ set.add(next.val); temp = temp.next; } } return head; 86.Partition List 分隔链表 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 你应当保留两个分区中每个节点的初始相对位置。 示例: 输入: head = 1->4->3->2->5->2, x = 3 输出: 1->2->2->4->3->5 解题思路:感觉链表的题都好难啊……但是看了别人的解法有感觉很简单,这道题的思路就是把小的和大的分别依次链起来,最后整合。 public ListNode partition(ListNode head, int x){ ListNode head1 = new ListNode(0); ListNode head2 = new ListNode(0); ListNode phead1 = head1; ListNode phead2 = head2; ListNode temp = head; while (temp!=null){ if(temp.val<x){ phead1.next = temp; temp = temp.next; phead1 = phead1.next; phead1.next = null; }else{ phead2.next = temp; temp = temp.next; phead2 = phead2.next; phead2.next = null; } } phead1.next = head2.next; head = head1.next; return head; } 328. Odd Even Linked List 奇偶链表 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 示例 1: 输入: 1->2->3->4->5->NULL 输出: 1->3->5->2->4->NULL 示例 2: 输入: 2->1->3->5->6->4->7->NULL 输出: 2->3->6->7->1->5->4->NULL 说明: 应当保持奇数节点和偶数节点的相对顺序。 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。 解题思路:这道题和上一道题的解题思路基本一致。将奇偶数节点分别链起来,最后再整合即可。需要注意的是需要记录奇偶节点的首节点的位置,方便整合。 public ListNode oddEvenList(ListNode head) { ListNode temp = head; ListNode evenNode = new ListNode(-1); ListNode oddNode = new ListNode(-1); ListNode pEvenNode = evenNode; ListNode pfirOddNode = oddNode; int i = 1; while (temp != null){ if(i%2==0){ evenNode.next = temp; evenNode = evenNode.next; temp = temp.next; evenNode.next = null; }else { oddNode.next = temp; oddNode = oddNode.next; temp = temp.next; oddNode.next = null; } i++; } oddNode.next = pEvenNode.next; head = pfirOddNode.next; return head; } 2.Add Two Numbers 两数相加 给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 解题思路:不得不说看别人的代码都赏心悦目,相比之下自己的代码不知道是哪个弱智写的。这道题同样不难,两两相加,遇到某个数字位数不够了补0就可以了。这里还是以leetcode上大佬写的代码为例 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode next = new ListNode(0); ListNode result = next; int add = 0; while (l1 != null || l2 != null) { int l1val = (l1 != null) ? l1.val : 0; int l2val = (l2 != null) ? l2.val : 0; int value = l1val + l2val + add; add = value / 10; next.next = new ListNode(value % 10); next = next.next; l1 = (l1 != null) ? l1.next : null; l2 = (l2 != null) ? l2.next : null; } if (add > 0) { next.next = new ListNode(add); } return result.next; } 203. Remove Linked List Elements 移除链表元素 删除链表中等于给定值 val 的所有节点。 示例: 输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5 解题思路: 利用虚拟头结点,删除所有重复元素即可。我的代码有些小瑕疵,应该释放删除掉节点的内存空间。 public ListNode removeElements(ListNode head, int val) { ListNode dummyNode = new ListNode(0); dummyNode.next = head; ListNode cur = dummyNode; while (cur.next!=null){ if(cur.next.val==val) cur.next = cur.next.next; else cur = cur.next; } return dummyNode.next; } 82. Remove Duplicates from Sorted List II 删除排序链表中的重复元素 II 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。 示例 1: 输入: 1->2->3->3->4->4->5 输出: 1->2->5 示例 2: 输入: 1->1->1->2->3 输出: 2->3 解题思路:总感觉链表题都挺有难度的,可能是平常用的少的原因吧。这道题其实思路也很简单,就是遇到相同节点,就循环往下找下一个不同的节点,并链接。 public ListNode deleteDuplicates(ListNode head) { ListNode dummyHead = new ListNode(0); dummyHead.next = head; ListNode prev = dummyHead; while (prev.next != null) { ListNode cur = prev.next; if (cur.next == null || cur.val != cur.next.val) { prev = prev.next; continue; } while (cur.next != null && cur.next.val == cur.val) { cur.next = cur.next.next; } prev.next = cur.next; } return dummyHead.next; }

优秀的个人博客,低调大师

leetcode算法题学习Java版(1)

队列和广度优先搜索 岛屿的个数 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/872/ 解题思路:广度优先,从某个为1的点开始,广度优先搜索他附近所有为1的点,将这些点的值改为2防止重复。计算有多少次将相邻的1改为2的次数,即为岛屿的次数。 class Solution { public int numIslands(char[][] grid) { if (grid == null || grid.length == 0 || grid[0].length == 0) return 0 ; int row = grid.length;//行数 int column = grid[0].length;//列数 int count = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { if (grid[i][j] == '1'){ count ++; combine(grid,i,j); } } } return count; } public static void combine(char[][] grid, int x, int y){ grid[x][y] = '2'; if (x > grid.length-1 && y > grid[0].length-1 ) { return; } if (x < grid.length-1 && grid[x+1][y] == '1') { //向下 combine(grid,x+1,y); } if (y < grid[0].length-1 && grid[x][y+1] == '1'){ //向右 combine(grid,x,y+1); } if (x > 0 && grid[x-1][y] == '1' ){ //向上 combine(grid,x-1,y); } if (y > 0 && grid[x][y-1] == '1') { //向左 combine(grid,x,y-1); } } } 打开转盘锁 你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。 锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。 列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。 字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。 https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/873/ 解题思路:将这道题看作是一道迷宫题,每次找一个数字当前能一步到的其他所有邻居数字,次数加1,所有邻居数字再找邻居数字的邻居数字,直到找到一个正确路径。 package com.ice.leetcode; import java.util.*; public class Solution { public static void main(String[] args) { String[] deadends = {"8887","8889","8878","8898","8788","8988","7888","9888"}; String target = "8888"; int count = openLock(deadends, target); System.out.println(count); } public static int openLock(String[] deadends, String target) { String start = "0000"; List<String> visited = new ArrayList<String>(); visited.add(start); Queue<String> queue = new LinkedList<String>(); int count = 0; queue.offer(start); while (!queue.isEmpty()) { int len = queue.size(); for (int i = 0; i < len; i++) { String top = queue.peek(); queue.poll(); List<String> neibors = findNeibors(top); for (String neibor:neibors) { if (target.equals(neibor)) { count++; return count; } if (findString(visited, neibor)) { continue; } if (!findString(Arrays.asList(deadends), neibor)) { visited.add(neibor); queue.offer(neibor); } } } count++; } return -1; } public static List<String> findNeibors(String s) { String temp = s; List<String> result = new ArrayList<>(); for (int i = 0; i < s.length(); i++) { char[] charTemp = temp.toCharArray(); charTemp[i] = String.valueOf((Integer.parseInt(String.valueOf(charTemp[i])) + 1) % 10).toCharArray()[0]; // charTemp[i] = (char) ((Integer.parseInt(String.valueOf(charTemp[i])) + 1) % 10); result.add(String.valueOf(charTemp)); charTemp[i] = String.valueOf((Integer.parseInt(String.valueOf(charTemp[i])) + 8) % 10).toCharArray()[0]; result.add(String.valueOf(charTemp)); } return result; } public static boolean findString(List<String> tofind, String s) { for (String temp : tofind) { if (s.equals(temp)) { return true; } } return false; } } 完全平方数 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 示例 1: 输入: n = 12 输出: 3 解释: 12 = 4 + 4 + 4. 示例 2: 输入: n = 13 输出: 2 解释: 13 = 4 + 9. https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/874/ 解题思路:这道题和上一道打开转盘锁思路基本一样,同样是使用广度优先,每遍历一层将count++。不同点在于,本题每层将一个数拆成一个完全平方数和另一个数之和,每次将另一个数加入队列,判断另一个数是否为完全平方数,否则,广度搜索他的下一层。 import static java.lang.Math.sqrt; class Solution { public int numSquares(int n) { int count = 0; Queue<Integer> queue = new LinkedList<>(); if(isSquare(n)){ return 1; } queue.offer(n); while(!queue.isEmpty()){ int len = queue.size(); for (int z=0;z<len;z++){ int top = queue.peek(); queue.poll(); for(int i=0;i<=sqrt(top);i++){ int m = top-i*i; if(isSquare(m)){ count +=2; return count; } if(m==top){ continue; } queue.offer(m); } } count++; } return count; } public static boolean isSquare(int n){ double temp = sqrt(n); int m = (int) temp; return m*m==n; } } 栈和深度优先搜索 有效的括号 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 解题思路:本题较简单,利用堆栈,遇到右括号即一直出栈,判断括号是否匹配 class Solution { public boolean isValid(String s){ Stack<String> stack = new Stack<String>(); for(int i =0;i<s.length();i++){ String temp = s.substring(i,i+1); if(temp.equals("}")||temp.equals("]")||temp.equals(")")){ if(stack.empty()){ return false; } while (!stack.empty()){ String top = stack.peek(); stack.pop(); if((top.equals("{")||top.equals("[")||top.equals("("))){ if(!matchBrackets(top,temp)){ return false; }else { break; } } } }else { stack.push(temp); } } if(stack.isEmpty()){ return true; } return false; } public static boolean matchBrackets(String a,String b){ if( (a.equals("{")&&b.equals("}")) || (a.equals("[")&&b.equals("]")) || (a.equals("(")&&b.equals(")")) ){ return true; } return false; } } 每日温度 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高,请输入 0 来代替。 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。 提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。 https://leetcode-cn.com/explore/learn/card/queue-stack/218/stack-last-in-first-out-data-structure/879/ 解题思路:本题利用栈,将气温不断入栈,判断下一个气温是否比栈顶的气温高,如果高,则不断出栈直到不比栈顶的温度高,如果,并逐个计算每个出栈元素与这个比他们高的气温的差值天数,最后将这个气温入栈,寻找下一个比他高的气温。直到栈空。 class Solution { public int[] dailyTemperatures(int[] temperatures) { Stack<Entry> stack = new Stack<Entry>(); int[] res = new int[temperatures.length]; for (int i = 0; i < temperatures.length; i ++) { if (stack.isEmpty()) { stack.push(new Entry(temperatures[i], i)); continue; } if (temperatures[i] <= stack.peek().val) stack.push(new Entry(temperatures[i], i)); else { int j = 1; while (!stack.isEmpty() && temperatures[i] > stack.peek().val) { Entry tmp = stack.pop(); res[tmp.index] = i - tmp.index; } stack.push(new Entry(temperatures[i], i)); } } return res; } private class Entry { public int val; public int index; public Entry(int val, int index) { this.val = val; this.index = index; } } } 逆波兰表达式求值 根据逆波兰表示法,求表达式的值。 有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 说明: 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 https://leetcode-cn.com/explore/learn/card/queue-stack/218/stack-last-in-first-out-data-structure/880/ 解题思路:本题很简单,不断入栈,遇到运算符就出栈前两位进行运算即可 class Solution { public int evalRPN(String[] tokens){ Stack<String> stack = new Stack<>(); for(int i =0;i<tokens.length;i++){ if(isSimbol(tokens[i])){ int temp1 = Integer.parseInt(stack.pop()); int temp2 = Integer.parseInt(stack.pop()); if(tokens[i].equals("+")){ stack.push(String.valueOf(temp1+temp2)); } if(tokens[i].equals("-")){ stack.push(String.valueOf(temp2-temp1)); } if(tokens[i].equals("*")){ stack.push(String.valueOf(temp1*temp2)); } if(tokens[i].equals("/")){ stack.push(String.valueOf(temp2/temp1)); } }else { stack.push(tokens[i]); } } return Integer.parseInt(stack.pop()); } public static boolean isSimbol(String s){ if(s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/")){ return true; } return false; } }

优秀的个人博客,低调大师

Python Flask学习知识点(七)

timg (11).jpg 静态文件访问原理 app文件夹下新建文件夹static,放入一张图片demo.jpg,然后访问服务器启动默认地址127.0.0.1:81/static/demo.jpg就可以访问到这张图片。 问:为什么Flask可以在任何代码不编写的情况下自动读取到static目录下的图片文件? 答:因为Flask对于静态文件是有默认值设置的,默认情况下,Flask认为静态文件夹的名字就叫ststic,并且位于应用程序的根目录下的,也就是app文件夹目录下。 image.png 问:为什么应用程序根目录是app目录而不是app上边的flaskDemo目录? 答:因为在实例化Flask核心对象是传入了一个参数,如下代码: def create_app(): app = Flask(__name__) app.config.from_object('app.secure') app.config.from_object('app.setting') register_blueprint(app) db.init_app(app) db.create_all(app=app) return app __name__这个参数决定了我们应用程序的根目录是app目录。 如果不想使用默认的static作为静态文件存储路径,可以通过更改配置来访问, app = Flask(__name__, static_folder='web/img') 更改成为这个路径,就要这样访问:127.0.0.1:81/img/demo.jpg, 还可以这么改: app = Flask(__name__, static_folder='web/img', static_path='') 但是我们一般还是使用Flask默认设置即可,如果确实有需求,具体使用详情请查阅官方文档。 静态文件放到蓝图中 之前说过,Flask里有两个层级: Flask核心对象:应用程序级别 蓝图 对于静态文件,也有两个级别: 应用程序static 蓝图static 如果你认为你的静态文件是针对你的蓝图的话,那么你其实是可以把静态文件注册到蓝图上边,而不是注册到应用程序上边。 image.png 蓝图的相关方法其实几乎就是复制了Flask核心对象的api,基本参数都是一致的。 蓝图注册静态文件夹: from flask import Blueprint # 蓝图 web = Blueprint("web", __name__, static_folder='', static_url_path='') 模板文件 模板就是html,但是和普通html不同,模板是没有数据的,它等待填充数据。 app文件夹下新建文件夹templates,新建html文件:test.html: image.png 同上边提到的static文件夹一样,我们可以自定义templates文件夹的位置,通过更改template_folder=参数来自定义templates文件夹的位置,例如,把templates文件夹移动到web文件夹下后需改动: 两种更改方法: Flask核心对象上更改:app = Flask(__name__, template_folder='web/templates') 在蓝图对象上更改:web = Blueprint("web", __name__, template_folder='templates') 现在要把视图函数中返回的数据填充到模板test.html中,使用Flask内置的方法:render_template() from flask import render_template @web.route('/test') def test(): r = { "name": "allen", 'age': 24 } r1 = { "name": "zhao", "age": 12 } return render_template('test.html', data=r, data1=r1) 模板语言 Jinja2 如何在模板中组织、解析相关数据 编辑test.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>demo</h1> {{data.age}} {{data1.age}} </body> </html> 运行代码,浏览器输入127.0.0.1:8000/test image.png 可以看到,之前我们写在视图函数中的数据已经展示到页面了。 Flask为了让我们很好的在模板解析和展示数据,它引入了一个模板引擎,叫做Jinja2。 Jinja2有自己的语法,例如注释代码:{#hello word#},这里就把hello word注释掉了。 我们的pycharm默认是不会像写python代码一样智能提示Jinja2的语法,但是,更改设置即可: image.png Jinja2也叫做模板语言, Flask官方推荐我们使用Jinja2,大家也可以自己使用其他的模板语言。

优秀的个人博客,低调大师

6.Swift学习之逻辑分支

一. 分支的介绍 分支语句即 if/switch/三目运算符等判断语句 通过分支语句可以控制程序的执行流程 二. if分支语句 和OC中if语句有一定的区别 判断句可以不加() 判断之后的执行语句必须用{}阔起来 在判断句中必须有明确的真假 不再有非0即真 必须有明确的Bool值 案例一 let a = 10 // 错误写法: //if a { // print("a") //} // 正确写法 if a > 9 { print(a) } 案例二 let score = 87 if score < 60 { print("不及格") } else if score <= 70 { print("及格") } else if score <= 80 { print("良好") } else if score <= 90 { print("优秀") } else { print("完美") } 案例三: // 这个是可选类型,因为只有声明成可选类型后,才可以判断是否为空 // 可选类型会在后续讲解,可先了解即可 let view : UIView? = UIView() // 判断如果view有值,则设置背景 // 错误写法 //if view { // view.backgroundColor = UIColor.red //} if view != nil { view!.backgroundColor = UIColor.red } 三. 三目运算符 Swift 中的 三目 运算保持了和 OC 一致的风格 var a = 10 var b = 50 var result = a > b ? a : b print(result) 四.guard的使用 guard是Swift2.0新增的语法,目的是提高程序的可读性 它与if语句非常类似,但不同的是当条件为false的时候执行 guard语句必须带有else语句,它的语法如下: 当条件表达式为true时候跳过else语句中的内容,执行后面的语句组 条件表达式为false时候执行else语句中的内容,跳转语句一般是return、break、continue和throw guard 条件表达式 else { // 条换语句 break } 语句组 例子 var age = 18 func online(age : Int) -> Void { guard age >= 18 else { print("回家去") return } print("可以上网") } online(age) 四.switch分支 switch的介绍 Switch作为选择结构中必不可少的语句也被加入到了Swift中 苹果对Switch进行了大大的增强,使其拥有其他语言中没有的特性 switch的简单使用 基本用法和OC用法一致 不同之处: switch后可以不跟() case后可以不跟break(默认会有break) case后多行语句可以不加() 例子 let sex = 0 switch sex { case 0 : print("男") case 1 : print("女") default : print("其他") } 补充一: 一个case判断中,可以判断多个值 多个值以,隔开 let sex = 0 switch sex { case 0, 1: print("正常人") default: print("其他") } 补充二: 如果希望出现之前的case穿透,则可以使用关键字fallthrough let sex = 0 switch sex { case 0: fallthrough case 1: print("正常人") default: print("其他") } Switch支持多种数据类型 浮点型的switch判断 let f = 3.14 switch f { case 3.14: print("π") default: print("not π") } 支持字符串类型(后面会讲字符串) let m = 5 let n = 10 var result = 0 let opration = "+" switch opration { case "+": result = m + n case "-": result = m - n case "*": result = m * n case "/": result = m / n default: result = 0 } print(result) switch支持区间判断 什么是区间? 数学中区间(0,10)、(0,10]、[0,10)、[0,10] swift中的区间常见有两种 半开半闭区间:0..<10 表示:0~9,不包括10 闭区间:0...10 表示:0~10 let score = 88 switch score { case 0..<60: print("不及格") case 60..<80: print("几个") case 80..<90: print("良好") case 90..<100: print("优秀") default: print("满分") }

优秀的个人博客,低调大师

Python 学习之进程与线程 「 上 」

进程与线程 进程:对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器(任务)就是启动一个浏览器进程。进程是系统中程序执行和资源分配的基本单位,每个进程都有自己的数据段、代码段和堆栈段。 线程:有些进程不止同时干一件事情,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事情,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread),线程是最小的执行单元。 实现多任务原理 现代操作系统比如 Mac OS X,UNIX,Linux,Windows 等,都支持“多任务”。多任务指的是操作系统可以同时运行多个任务,比如同时在聊 QQ,听音乐,码字… 单核CPU实现多任务原理:CPU执行代码都是顺序执行的,操作系统轮流让各个任务交替执行,QQ 执行 2us 秒,切换到听音乐,听音乐执行 2us 秒,再切换到 word,执行 2us 秒…每个任务都是交替执行的,但是由于CPU的调度执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。 多核CPU实现多任务原理:真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。 并行与并发 并发:看上去同时执行,任务数多于核心数并行:真正同时执行,任务数小于等于核心数 多任务的实现方式: 多进程模式 多线程模式 协程模式 多进程+多线程模式 单进程(任务)现象 代码块 fromtimeimportsleepdefrun(): while1: print("执行子进程") sleep(1)if__name__=="__main__": while1: print("执行父进程")#父进程不结束,子进程无法开始 sleep(1) run()#不会执行到run方法,只有上面的while循环结束才可以执行 运行结果 多进程(任务)现象 1.任务间互不干扰 启动进程执行多任务,各个任务间互不干扰。multiprocessing库,跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象 代码块 frommultiprocessingimportProcessfromtimeimportsleepimportosdefrun1(num): while1: #getpid()获取当前进程id号,getppid()获取当前进程的父进程id号 print("执行子进程-%s"%num,os.getpid(),os.getppid()) sleep(2)defrun2(num): while1: print("执行子进程-%s"%num) sleep(3)if__name__=="__main__": while1: print("启动父(主)进程",os.getpid()) #创建子进程target:进程执行的任务,args为元组类型 p1=Process(target=run1,args=("01",)) p1.start()#启动进程 p2=Process(target=run2,args=("02",)) p2.start()#启动进程 whileTrue: print("执行主进程") sleep(1) 运行结果 2. 任务间相互干扰 事实上同时执行的各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务1必须暂停等待任务 2 完成后才能继续执行,有时,任务 3 和任务 4 又不能同时执行。所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程、单线程的程序。 代码块 frommultiprocessingimportProcessfromtimeimportsleepdefrun(num): print("子进程启动") sleep(2) print("子进程结束")if__name__=="__main__": print("父进程启动") #创建多个子进程,此处以一个为例 p=Process(target=run,args=("1",)) p.start() #未加入join()方法时,父进程的结束不影响子进程。为了让父进程等待所有的子进程结束后再继续执行父进程,需要添加一个join()方法,通常用于进程间的同步 p.join() print("父进程结束") 运行结果 3.启动大量子进程 以进程池的方式来批量创建多个子进程,体现多任务的并发执行 代码块 frommultiprocessingimportPoolimporttime,os,randomdefrun(num): print("子进程%d启动--%s"%(num,os.getpid())) start=time.time() time.sleep(random.choice([1,2,3])) end=time.time() print("子进程%d结束--%s--耗时%.2f"%(num,os.getpid(),end-start))if__name__=="__main__": print("父进程启动") #以进程池来创建多个进程,Pool默认大小是CPU核心数,表示可以同时执行的进程数量 p=Pool() foriinrange(10): #创建进程,放入进程池统一管理 p.apply_async(run,args=(i,)) #在调用join()之前必须先调用close(),调用close()之后就不能再继续添加新的进程了 p.close() #进程池对象调用join(),会等待进程池中所有的子进程结束完再去执行父进程 p.join() print("父进程结束") 运行结果 4.1文件拷贝(单进程) 当拷贝的文件量很少时,单进程的方式比较快,因为多进程需要先创建进程花费时间;当拷贝的文件量很大很多时,多进程的优势就体现出来了。例子中拷贝的是大小为 446 M 的多张图片,多进程花费的时间较少。 代码块 importos,time#实现文件的拷贝,此处文件大小为446MdefcopyFile(rPath,wPath): fr=open(rPath,"rb") fw=open(wPath,"wb") content=fr.read() fw.write(content) fr.close() fw.close() path=r"C:\Users\Mark\Pictures\pic1\12" toPath=r"C:\Users\Mark\Pictures\pic1\14"#读取path下的所有文件 filesList=os.listdir(path)#启动for循环处理每一个文件 start=time.time()forfileNameinfilesList: copyFile(os.path.join(path,fileName),os.path.join(toPath,fileName)) end=time.time() print("总耗时:%0.2f"%(end-start))#总耗时:19.03 4.2文件拷贝(多进程) 代码块 importos,timefrommultiprocessingimportPool#实现文件的拷贝defcopyFile(rPath,wPath): fr=open(rPath,"rb") fw=open(wPath,"wb") content=fr.read() fw.write(content) fr.close() fw.close() path=r"C:\Users\Mark\Pictures\pic1\12" toPath=r"C:\Users\Mark\Pictures\pic1\14"if__name__=="__main__": #读取path下的所有文件 filesList=os.listdir(path) #启动for循环处理每一个文件 start=time.time() p=Pool() forfileNameinfilesList: p.apply_async(copyFile,args=(os.path.join(path,fileName),os.path.join(toPath,fileName))) p.close() p.join() end=time.time() print("总耗时:%0.2f"%(end-start))#总耗时:15.76 5.封装进程对象 一般而言,父进程主要是负责调度子进程的执行,不具体负责某项任务,所以需要进行封装进程对象。将实现各个功能、任务的子线程封装起来,父线程只需负责调用,提高了代码的逻辑与整洁性。 代码块 父进程调用代码 fromchildProcessimportchildProcessif__name__=="__main__": print("父进程启动") #创建子进程 p=childProcess("01") #自动调用p进程对象的run方法 p.start() p.join() print("父进程结束") 子进程实现功能代码 frommultiprocessingimportProcessimportos,timeclasschildProcess(Process): def__init__(self,num): Process.__init__(self) self.num=num defrun(self): print("子进程(%s--%s)启动"%(self.num,os.getpid())) #子进程的功能 time.sleep(3) print("子进程(%s--%s)结束"%(self.num,os.getpid())) 运行结果 原文发布时间为:2018-08-06 本文作者:Python 梦工厂 本文来自云栖社区合作伙伴“Python梦工厂”,了解相关信息可以关注“Python梦工厂”。

优秀的个人博客,低调大师

机器学习笔记——特征标准化

数据标准化是在特征处理环节必不可少的重要步骤。 数据标准化是为了消除不同指标量纲的影响,方便指标之间的可比性,量纲差异会影响某些模型中距离计算的结果。 常见标准化方法主要有归一化、正态化。 数据归一化也即0-1标准化,又称最大值-最小值标准化,核心要义是将原始指标缩放到0~1之间的区间内。相当于对原变量做了一次线性变化。 其公式为 EX = (x- min)/(max - min) 另一种常用的标准化方法是z-score标准化,将原始指标标准化为均值为0,标准化为1的正态分布。 EX = (x - mean)/σ R语言中的特征标准化: library("caTools") library("scales") data(iris) split = sample.split(iris$Species,SplitRatio = .8) train_data = subset(iris,split == TRUE) test_data = subset(iris,split == FALSE) train_data[,-5] = apply(train_data[,-5],2,rescale,to = c(0,1)) test_data[,-5] = apply(test_data[,-5],2,rescale,to = c(0,1)) 以上scales包中的rescale函数可以自动完成指标中0-1标准化的任务,事实上,它可以将原始指标线性变化到任何一个数字区间内。 我们可以来验证结果是否是可信的。 range(train_data[,1]) range(apply(train_data[,-5],2,rescale,to = c(0,1))[,1]) [1] 4.3 7.7 [1] 0 1 当然你也可以自己写一个叫简单的0-1标准化函数 scale1 = function(x){ (x - min(x))/(max(x) - min(x)) } range(apply(train_data[,-5],2,scale1)[,1]) [1] 0 1 z-score标准化 z-score标准化可以通过scale函数快速实现。 train_data[,-5] = scale(train_data[,-5]) mean(train_data[,1]);sd(train_data[,1]) [1] 5.869167 [1] 0.8259241 mean(scale(train_data[,-5])[,1]);sd(scale(train_data[,-5])[,1]) [1] 0 [1] 1 #自定义一个z-score标准化函数 z_norm = function(x){ (x - mean(x))/sd(x) } mean(apply(train_data[,-5],2,z_norm)[,1]);sd(apply(train_data[,-5],2,z_norm)[,1]) [1] 0 [1] 1 Python中sk-learn库中有专门用于处理以上两种标准化的函数。 from sklearn import preprocessing from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris import pandas as pdimport numpy as np iris = load_iris() data = iris['data'] iris_data = pd.DataFrame( data = data, columns = ['sepal_length','sepal_width','petal_length','petal_width'] ) iris_data["Species"] = iris[ 'target'] iris_data["Species"] = iris_data["Species"].map({0:"setosa",1:"versicolor",2:"virginica"}) x,y = iris_data.iloc[:,0:-1],iris_data.iloc[:,-1] train_data,_data,train_target,test_target = train_test_split(x,y,test_size = 0.2,stratify = y) Python中的0-1标准化 min_max_scaler = preprocessing.MinMaxScaler() #实例化0-1标准化方法 X_train_minmax = min_max_scaler.fit_transform(test_data.iloc[:,0:4].values) X_test_minmax = min_max_scaler.transform(test_data.iloc[:,0:4].values) X_train_minmax[:,0].max() - X_train_minmax[:,0].min()1.0 Python中的z-score标准化 训练集第一列的均值和方差如下 train_data.iloc[:,0].mean();train_data.iloc[:,0].std() 5.86166666666666 40.8416853174847874 sc_X = preprocessing.StandardScaler() #实例化z-score标准化方法 X_train = sc_X.fit_transform(train_data.iloc[:,0:4].values) X_test = sc_X.transform(test_data.iloc[:,0:4].values) 标准化后第一列的均值和方差 X_train[:,0].mean();X_train[:,0].std() -2.2907601741432396e-151.0 以上仅介绍了最常用的两种标准化特征的方法及其实现,标准化的方法还有很多,对于什么的模型需要使用标准化以及适用什么方法的标准化,需要视具体场景和数据量级差异而定,小编也在摸索中。 标准化一方面可以防止原始特征中量纲差异影响距离运算(比如欧氏距离的运算)。 另一方面标准化也可以在一定程度上提升算法求解的效率。 原文发布时间为:2018-09-23 本文作者:杜雨 本文来自云栖社区合作伙伴“数据小魔方”,了解相关信息可以关注“数据小魔方”。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册