基础二分查找总结

前言

由于我在学习二分查找的过程中处于会了忘,忘了复习的状态,因此总结一套适合自己记忆的模板。建议先看参考资料\(^{[1,2,3]}\),理解二分查找各种细节的由来。

  1. 二分查找又死循环了?【基础算法精讲 04】
  2. 手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找
  3. 我写了首诗,让你闭着眼睛也能写对二分搜索

左闭右开的形式:循环条件一定是 while(left < right)。由于左闭,所以 left = mid + 1;。由于右开,所以 right = mid;。最后循环结束时,left == right

左闭右闭的形式:循环条件一定是 while(left <= right)。由于左闭,所以 left = mid + 1;。由于右闭,所以 right = mid - 1;。最后循环结束时,left == right + 1

确保上面段话能理解,为了方便记忆,优先采用左闭右开的形式。因为循环结束时,left == right,我觉得简单一点。

基础的二分查找

力扣链接:704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

左闭右开代码实现

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length;  // 定义target在左闭右开的区间里,即:[left, right)
        while(left < right){  // 因为left == right的时候,在[left, right)是空区间,所以使用小于号
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right)中
            }else if(nums[mid] > target){  
                right = mid;  // target 在左区间,在[left, mid)中
            }else{  // nums[mid] == target
                return mid;  // 数组中找到目标值,直接返回下标
            }
        }
        return -1;  // 未找到目标值
    }
}

左闭右闭代码实现

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;  // // 定义target在左闭右开的区间里,即:[left, right)
        while(left <= right){  // 因为left == right的时候,在[left, right]还有一个元素,所以使用小于等于号
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right]中
            }else if(nums[mid] > target){
                right = mid - 1;   // target 在左区间,在[left, mid - 1]中
            }else{
                return mid;  // // 数组中找到目标值,直接返回下标
            }
        }

        return -1;  // 未找到目标值
    }
}

lower_bound 和 upper_bound

lower_bound

lower_bound 含义:

  • 返回第一个大于等于 target 的位置,如果所有元素都小于 target,则返回数组的长度。
  • 在不改变原有排序的前提下,找到第一个可以插入 target 的位置。

左闭右开代码实现

int lower_bound(int[] nums, int target){
    int left = 0, right = nums.length;
    while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
        int mid = left + (right - left) / 2;
        if(nums[mid] < target){
            left = mid + 1;  // target 在右区间,在[mid + 1, right)中
        }else{
            right = mid;  // target 在左区间,在[left, mid)中
        }
    }
    return left;  // 此时 left == right,返回 right 也可以
}

对于 nums[mid] == target 的情况:
此时找到一个目标值 target,然而左边可能还有 target。由于要找的是第一个大于等于 target 的位置,所以应该向左区间继续查找,因此与 else 分支合并。

左闭右闭代码实现

int lower_bound(int[] nums, int target){
    int left = 0, right = nums.length - 1;
    while(left <= right){  // 定义target在左闭右闭的区间里,即:[left, right]
        int mid = left + (right - left) / 2;
        if(nums[mid] < target){
            left = mid + 1;  // target 在右区间,在[mid + 1, right]中
        }else{
            right = mid - 1;  // target 在左区间,在[left, mid - 1]中
        }
    }
    return left;  // 此时 left == right + 1
}

这里和左闭右开形式不同,左闭右开 left == right,不用纠结。这里 left == right + 1,有时候搞不清楚是返回 leftright,还是 left - 1......

这里有个方便记忆的小技巧,假设 leftright 都指向 target,再看下一步的结果。

比如下面这个例子,target == 3lower_bound 要求的结果就是红色的3。

此时 left == right,根据代码,应该执行 right = mid - 1; 这条语句,执行之后,如下图所示。

此时,left == right + 1,循环结束,结果应该为 left,所以 return left;

upper_bound

upper_bound 含义:

  • 返回第一个大于 target 的位置,如果所有元素都小于等于 target,则返回数组的长度。
  • 在不改变原有排序的前提下,找到最后一个可以插入 target 的位置。

左闭右开代码实现

int upper_bound(int[] nums, int target){
    int left = 0, right = nums.length;
    while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
        int mid = left + (right - left) / 2;
        if(nums[mid] <= target){
            left = mid + 1;  // target 在右区间,在[mid + 1, right)中
        }else{
            right = mid;  // target 在左区间,在[left, mid)中
        }
    }
    return left;  // 此时 left == right,返回 right 也可以
}

对于 nums[mid] == target 的情况:
此时找到一个目标值 target。由于要找的是第一个大于 target 的位置,所以应该向右区间继续查找,所以与 if 分支合并。

左闭右闭代码实现

int upper_bound(int[] nums, int target){
    int left = 0, right = nums.length - 1;
    while(left <= right){  // 定义target在左闭右闭的区间里,即:[left, right]
        int mid = left + (right - left) / 2;
        if(nums[mid] <= target){
            left = mid + 1;  // target 在右区间,在[mid + 1, right]中
        }else{
            right = mid - 1;  // target 在左区间,在[left, mid - 1]中
        }
    }
    return left;  // 此时 left == right + 1
}

lower_bound 类似,说一下记忆 return left; 的技巧。

假设 leftright 都指向 target,再看下一步的结果。

比如下面这个例子,target == 3upper_bound 要求的结果就是红色的4。

此时 left == right,根据代码,应该执行 left = mid + 1; 这条语句,执行之后,如下图所示。

此时,left == right + 1,循环结束,结果应该为 left,所以 return left;

可以看到,在左闭右闭的情况下,lower_boundupper_bound 都返回 left

lower_bound 和 upper_bound 的联系

可以发现,这两个函数只有 if 判断为相等的情况不同[6]。为方便记忆,在 if else 只有二分支的情况下,即把相等的情况归为 if 分支或 else 分支(不是 if ... else if ... else ... 三分支的情况)。

此时,lower_boundupper_bound 可以通过在 if 分支判断语句中增删 = 互相转化。

另外,upper_bound 可以直接复用 lower_bound
对于非递减整数数组,\(>x\) 等价于 \(\geq x+1\)[1]upper_bound 求第一个大于 target 的位置,就等价于 lower_bound 求第一个大于等于 target + 1 的位置。

因此,upper_bound 的另一种写法

int upper_bound(int[] nums, int target){
    return lower_bound(nums, target + 1);
}

所以,只要记 lower_bound 的代码就好了。

力扣相关题目

35. 搜索插入位置

力扣链接:35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

解法一
直接应用 lower_bound

class Solution {
    public int searchInsert(int[] nums, int target) {
        return lower_bound(nums, target);
    }

    int lower_bound(int[] nums, int target){
        int left = 0, right = nums.length;
        while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right)中
            }else{
                right = mid;  // target 在左区间,在[left, mid)中
            }
        }
        return left;  // 此时 left == right,返回 right 也可以
    }
}

解法二
通过 upper_bound 转化

class Solution {
    public int searchInsert(int[] nums, int target) {
        int pos = upper_bound(nums, target);
        if(pos == 0 || nums[pos - 1] != target) return pos;  // target 不存在
        return pos - 1;  // target 存在,前一个位置就是 target
    }

    int upper_bound(int[] nums, int target){
        int left = 0, right = nums.length;
        while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
            int mid = left + (right - left) / 2;
            if(nums[mid] <= target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right)中
            }else{
                right = mid;  // target 在左区间,在[left, mid)中
            }
        }
        return left;  // 此时 left == right,返回 right 也可以
    }
}

直接记解法一就行了,解法二只是证明 upper_bound 也可以做,因为 lower_boundupper_bound 本来就有转化关系。

34. 在排序数组中查找元素的第一个和最后一个位置

力扣链接:34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

思路
第一个位置:就是 lower_bound 函数的含义。
最后一个位置:如果 target 存在的话,第一个大于 target 的位置减一就是 target 的最后一个位置。

代码实现

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int start = lower_bound(nums, target);
        if(start == nums.length || nums[start] != target) return new int[]{-1, -1};  // target 不存在
        int end = upper_bound(nums, target) - 1;
        return new int[]{start, end};
    }

    int lower_bound(int[] nums, int target){
        int left = 0, right = nums.length;
        while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right)中
            }else{
                right = mid;  // target 在左区间,在[left, mid)中
            }
        }
        return left;  // 此时 left == right,返回 right 也可以
    }

    int upper_bound(int[] nums, int target){
        return lower_bound(nums, target + 1);
    }
}

69. x 的平方根

力扣链接:69. x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去

注意: 不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

思路
这其实就是一个 upper_bound 问题,对于 x = 8,二分区间应该在 [0,8],我们要在这些数的平方中找到第一个大于8的数,它左边的那个数的平方根就是答案。如下图所示,找到9(是第一个大于8的数),左边4的平方根2就是答案。

代码
直接应用 upper_bound,下面的代码会超出内存限制,但是方便我们理解它和 upper_bound 的关系。

class Solution {
    public int mySqrt(int x) {
        int[] nums = new int[x + 1];
        for(int i = 0; i <= x; i++) nums[i] = (i + 1) * (i + 1);
        int res = upper_bound(nums, x);
        return res;
    }

    int lower_bound(int[] nums, int target){
        int left = 0, right = nums.length;
        while(left < right){  // 定义target在左闭右开的区间里,即:[left, right)
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;  // target 在右区间,在[mid + 1, right)中
            }else{
                right = mid;  // target 在左区间,在[left, mid)中
            }
        }
        return left;  // 此时 left == right,返回 right 也可以
    }

    int upper_bound(int[] nums, int target){
        return lower_bound(nums, target + 1);
    }
}

左闭右开代码
由于 x + 1 可能溢出,所以要用 long

class Solution {
    public int mySqrt(int x) {
        long left = 0, right = (long) x + 1;  //左闭右开,所以是[0,x+1)
        while(left < right){
            long mid = left + (right - left) / 2;
            if(f(mid) <= x){
                left = mid + 1;
            }else{
                right = mid;
            }
        }

        return (int)(left - 1);
    }

    long f(long x){  // 计算x的平方
        return (long) x * x;
    }
}

左闭右闭代码

class Solution {
    public int mySqrt(int x) {
        int left = 0, right = x;  //左闭右闭,所以是[0,x]
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(f(mid) <= x){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }

        return left - 1;
    }

    long f(int x){  // 计算x的平方
        return (long) x * x;
    }
}

367. 有效的完全平方数

力扣链接:367. 有效的完全平方数

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如  sqrt 。

示例 1:

输入:num = 16
输出:true
解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。

示例 2:

输入:num = 14
输出:false
解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。

左闭右开代码
由于 x + 1 可能溢出,所以要用 long

class Solution {
    public boolean isPerfectSquare(int num) {
        long left = 1, right = num + 1;  //左闭右开,所以是[0,x+1)
        while(left < right){
            long mid = left + (right - left) / 2;
            long square = mid * mid;
            if(square < num){
                left = mid + 1;
            }else if(square > num){
                right = mid;
            }else{
                return true;
            }
        }

        return false;
    }
}

左闭右闭代码

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 1, right = num;  //左闭右闭,所以是[0,x]
        while(left <= right){
            int mid = left + (right - left) / 2;
            long square = (long) mid * mid;
            if(square < num){
                left = mid + 1;
            }else if(square > num){
                right = mid - 1;
            }else{
                return true;
            }
        }

        return false;
    }
}

二分查找进阶

以上是基础的二分查找类型,对于进阶的题目,把问题转化成二分查找是一个难点。

参考资料

  1. 二分查找又死循环了?【基础算法精讲 04】
  2. 手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找
  3. 我写了首诗,让你闭着眼睛也能写对二分搜索
  4. C++中的upper_bound和lower_bound区别
  5. 34. 在排序数组中查找元素的第一个和最后一个位置
  6. 用Java实现C++::std中的upper_bound和lower_bound

以上是我个人的学习心得,能力有限,如有错误和建议,恳请批评指正!

本文转载于网络 如有侵权请联系删除

相关文章

  • 『操作系统』微内核结构的操作系统几何?(优缺点)

    微内核操作系统微内核操作系统,即实现了一个可在其上构建通用OS的基础内核,该内核程序运行在核心态,开机常驻内存。当前微内核操作系统结构仍没有一致公认的定义,但可从以下4方面进行描述:足够小的内核:微内核并非一个完整的OS。与硬件紧密相关,实现较基本功能,复杂客户和服务器通信应用机制与策略分离原理:机制用于实现某一功能的具体执行机构,位于基层;策略借助某些参数和算法实现功能优化或达到不同功能目标,位于高层采用面向对象技术基于C/S模式微内核包含的基本功能有:进程管理、低级存储管理、中断和陷入处理等,调度算法、虚拟内存的页面置换算法等都放入外部服务器中实现。优点1)灵活性高易扩展由于微内核OS的许多功能是由相对独立的服务器软件来实现的,当开发了新的硬件和软件时,微内核OS只须在相应的服务器中增加新的功能,或再增加一个专门的服务器。与此同时,也必然改善系统的灵活性,不仅可在操作系统中增加新的功能,还可修改原有功能,以及删除已过时的功能,以形成一个更为精干有效的操作系统。2)可靠性强由于所有服务器都是运行在用户态,服务器与服务器之间采用的是消息传递通信机制,因此,当某个服务器出现错误时,不会影

  • Excel实战技巧109:快速整理一列数据拆分成多列

    如果你的工作簿中的数据如下图1所示。图1而你想把它们转换成如下图2所示。图2你可以使用多种方法,包括:使用VBA,创建数组公式,编写多个公式,等等。本文将给你展示一种“最懒的”方法,也可能是最快且最容易的方法。第1步:设置标题如下图3所示,在单元格E3:G3中输入标题。图3第2步:创建引用公式在单元格E4至G4中创建单元格引用,如下图4所示代表想要看到的单元格中的数据。图4第3步:将等号更换为“Ex”使用“Ex”替换掉单元格E4至G4中的等号,如下图5所示。图5第4步:创建模式引用我们需要发现原始数据中商品名称、销售额和利润所出现的模式,每次出现均间隔3行。于是,在单元格E5到G5中创建第2行引用,相对于上一行中的数字相差3,如下图6所示。图6第5步:创建整个引用列表现在,我们已经建立了Excel的工作模式,选择所有引用单元格(E4:G5),单击并按住填充系列手柄并向下拖动,生成一个列表,该列表超过了15行,以便稍后扩展列表。如下图7所示。图7第6步:将“Ex”引用转换成真实的公式选择包含“Ex”的所有单元格,按下Ctrl+H组合键,弹出“查找和替换”对话框。在“查找内容”中输入“Ex

  • 文件切割合并器&nbsp;4&nbsp;帮助类&nbsp;Help

    importjava.awt.BorderLayout;importjavax.swing.JFrame;importjavax.swing.JPanel;importjavax.swing.JScrollPane;importjavax.swing.JTextArea;publicclassHelpextendsInitFrame{privatestaticfinallongserialVersionUID=1L;publicHelp(){super("文件切割合并器—帮助","file_split.png",420,250);//this.setResizable(false);initGUI();this.setVisible(true);}privatevoidinitGUI() {//设置布局this.setLayout(newBorderLayout());JTextAreatextArea=newJTextArea(10,35);textArea.setEditable(false);textArea.append("文件

  • 明日直播|如何在保障在线业务服务质量前提下,提升服务器资源利用率?

    腾讯云主办首个云原生百科知识直播节目——《云原生正发声》,每周二晚19:30开播。《云原生正发声》围绕云原生技术领域,覆盖实时的云原生技术实践、性能优化、前沿趋势、当前热点、案例分享、大咖分享、开发者成长路径、就业方向选择等等内容。上周我们分享了"Caelus—基于K8s全场景在离线混部技术实践"的技术专题,受到技术开发爱好者们的踊跃追捧及频繁的在线问答交流。还没有收看的同学也不用着急,我们所有的分享都有直播回放,手指滑倒底部,就可以看到【云原生正发声】的全部直播回放哦~上次直播的交流过程中,很多同学提到关于”CPU资源利用“、”服务器层面的资源QoS“等技术内容,想了解更多,其实这些问题都会在我们明天6月22日直播分享得到解答哦~明晚6月22日19:30,腾讯云高级工程师李弘博,将与我们一起聚焦腾讯TencentOS的服务器资源QoS,向大家介绍我们如何在保障在线业务服务质量的前提下,提升服务器资源利用率。不要再犹豫啦~赶紧扫码或者点击【阅读原文】报名吧~ ·往期直播视频回顾 ·(建议保存收藏哦) 第一期:多种模式下的深度学习弹性训练第二期:如何在Istio服务网

  • RedTeam之ReverseTCPShell

    大家好啊,我是我们实验室的Mr.赵,几天前,一师傅就在说这个工具,正好,这个工具今天就出来了,我们一起来常常鲜,由于kali已经支持powershell了,这里我们就直接使用kali来演示了。先奉上原作者的演示视频: 界面简单无比,十分符合老外的个性,ReverseTCPShellC2,正如其名,是一款powershell编写的反弹shell工具,流量经过AES加密,据说可以bypass,上手看看吧。提供了3种payload的混淆的方式:ASCII、xor、Base64,这里随便选择xor也是直接给出来了PS下的和CMD下的利用,并监听4444端口靶机上线,waf无拦截简单命令执行:常见的文件上传、下载啥的自然也是可以的至于实现方式也是很容易就能看出来的,三个函数ASCLLfunctionASCII_Obfuscation($String) { $PowerShell="IEX(-Join((@)|%{[char]`$_}));Exit"; $CMD="ECHO`"IEX(-Join((@)|%{[char]```$_}));Exit`"

  • LeetCode 42. Trapping Rain Water

    题目1A c++O(n^2)classSolution{ public: inttrap(vector<int>&height){ intans=0; for(inti=1;i<height.size();i++) { if(height[i]>height[i-1]) { intpos=0; for(intj=i-2;j>=0;j--) { if(height[j+1]<height[j]) { inth=min(height[j],height[i]); for(intk=j+1;k<=i-1;k++) { ans+=h-height[k]; height[k]+=h-height[k]; } if(height[i]<height[j]) break; } } } } returnans; } };复制O(n)classSolution{ public: intleft[100005]; intright[100005]; inttrap(vector<int>&height){ inta

  • “钢铁直猿”专属,5·20硬核表白方式三连击

    作者:曹培信一年一度的狗粮大会又要在这骚动的春夏之交“5·20”开始了,面对情人节、“5·20”、七夕以及各种各样的纪念日里,如何向自己的女朋友表达爱意?总有程序员会手足无措,在他们眼里,女朋友和产品经理似乎有点像——永远都搞不懂他们要什么!但也不乏浪漫的程序员会用技术制造惊喜。例如西班牙程序员RomanCortes就曾经用纯javascript脚本编写了一个3D红玫瑰,它是由显式分段三维曲面的蒙特卡罗采样生成的。感兴趣的同学可以戳下面的链接:http://www.romancortes.com/blog/1k-rose/既然有前辈带路,这群“钢铁直猿”们也想出了各种各样的硬核方式向自己的女朋友(或心仪的对象)表达爱意,什么?你还没有对象?那就先new一个对象吧。文摘菌从其中选取三个代表性而且比较容易上手的项目,并给出现成的代码,算是为了大家的幸福做出的一点微小的事情吧~如果要求不高,那就简简单单画个爱心Python的turtle包真的是非常好用哈,上次文摘菌画皮卡丘也是用的这个。话不多说,给大家看看效果:没有什么是用python画一个爱心解决不了的,如果有,那就画两个。想表白怕被拒?

  • CovertBand:连“啪啪啪”都能识别的身体运动信息测试

    近期,华盛顿大学PaulG.Allen计算机学院通过研究,实现了一种基于声纳并名为CovertBand的测试,通过该测试,可以对特定范围和有隔离屏障内目标人物的位置及身体运动信息进行捕捉,进而推断出目标人物的当前身体运动状况,甚至连”啪啪啪”运动也能被识别!在提倡数据安全和隐私保护的今天,该项研究试图证明,在毫不知情的前提下,你的身体运动动信息可能正被测试者能通过智能设备进行窃取。实现方法把CovertBand测试应用伪装一个第三方安卓手机APP,设法在目标人物手机上成功完成安装后,当手机播放音乐或语音时,该APP会调用安卓系统的AudioTrack接口,混淆在其中,隐蔽发射频率为18-20kHz特定构造的音频信号;同时,测试者调用安卓系统的AudioRecord接口,录制18-20kHz特定音频信号产生的背散射信号。之后,测试者可以使用笔记本电脑通过蓝牙接收经录制过的背散射信号,判断出目标人物的2D空间位置,结合不同位置的信号反映,最终可以综合判断出目标人物的身体活动信息。实用场景监控测试假如Alice是一个去国外执行监控任务的间谍,她在监控对象Bob所住酒店隔壁租住了一间房间,打算

  • ASP.NET:创建Linked ValidationSummary, 深入理解ASP.NET的Validation

    我想对于ASP.NET的Validator控件已经熟悉的不能再熟悉了。我们已经习惯了用Validator控件来验证我们在表单的输入,并通过ValidationSummary来输出我们为Validator控件设置的Errormessage。不知道大家有没想过进一步改进一下我们的Validation来改善我们的UserExperience。比如,在ValidationSummary输出一个Link连接到对应的控件,而不是显示单纯的Errormessage。 比如在上图中,是一个典型的Login的Page。我们有两个必填的字段:Username和Password。为此我定义两个RequiredFieldValidator。他们的Errormessage分别为:”Usernameismandatory!”和”Passwordismandatory!”。在未输入任何值得前提下Click“Signin”按钮,ErrorMessage被显示在ValidationSummary上面。不过和传统的Errormessage不同,显示在ValidationSummary上的实际上是两个链接,Click对应的

  • 通用Web后台魔方NewLife.Cube

    魔方是一个基于ASP.NETMVC的用户权限管理平台,可作为各种信息管理系统的基础框架。 演示:http://cube.newlifex.com 源码 源码: http://git.newlifex.com/NewLife/NewLife.Cube海外: https://github.com/NewLifeX/NewLife.Cube 特性 通用权限管理,用户、角色、菜单、权限,支持控制器Action权限控制 多数据库,支持 SQLite/SqlServer/Oracle/MySql/SqlCe/Access 免部署,系统自动创建数据库表结构,以及初始化数据,无需人工干涉 强大的视图引擎,支持子项目视图重写父项目相同位置视图,任意覆盖修改默认界面 系统要求 IIS7.0 .NETFramework4.5 ASP.NETMVC5 SQLite /SqlServer/Oracle/MySql/SqlCe/Access 安装 在 VisualStudio 中新建MVC5项目 通过 NuGe

  • 网站操作备忘

    flash不能使用。安装FlashPlayer官方下载中心-Flash中国官网 ,在这个软件中访问链接。 通过ssh秘钥登录服务器命令   ssh-i"/Users/zhoujingen/ealearning.pem"root@服务器地址 查找软件安装路径whereisnginx 拷贝目录下所有文件到另一个目录下,包括文件权限cp-p-r./bizbok/./projecttoproduct/ 移动文件mv  mv/virtualhost/KZYJSlBlPlL/bizbok.cn_bundle.crt /usr/local/nginx/conf  mv/virtualhost/KZYJSlBlPlL/bizbok.cn.key /usr/local/nginx/conf  在Nginx根目录下,通过执行以下命令验证配置文件问题。  ./sbin/nginx-t 在Nginx根目录下,通过执行以下命令重载Nginx。  ./sbin/nginx-srel

  • 阿里云(ECS)Linux客户端SSH会话连接超时OperationTimedOut

    问题描述:使用SecureCRT等SSH客户端连接Linux服务器时,提示Operationtimedout。 问题原因:SSH服务未配置或注释掉向SSH客户端连接会话发送频率和时间。 解决方法:在/etc/ssh/sshd_config配置服务器向SSH客户端连接会话发送频率和时间,并重启SSH服务。 vi/etc/ssh/sshd_config(添加或修改以下配置) ClientAliveInterval60(每隔多少秒给SSH客户端发送一次信号)ClientAliveCountMax86400(超过多少秒后断开与SSH客户端连接)systemctlrestartsshd.service复制   本文出自:http://www.cnblogs.com/linxx,本博客文章除特别声明,全部都是原创或亲身实践过,禁止个人和公司转载本文,谢谢理解!

  • 基于TLSR8359的2.4G私有协议多发一收方案解析

    一简析 1.简介 泰凌微的2.4G私有协议芯片在市场应用十分广泛。 2.特性 无线传输距离远 功耗低,接口丰富 自带mcu功能,可实现mcu+2.4G的私有功能 二源码解析 1.原理图 框图如下所示     2.源码解析 A设置数据包的信息 gen_fsk_preamble_len_set(4); gen_fsk_sync_word_len_set(SYNC_WORD_LEN_4BYTE); gen_fsk_sync_word_set(GEN_FSK_PIPE0,sync_word); gen_fsk_pipe_open(GEN_FSK_PIPE0); gen_fsk_tx_pipe_set(GEN_FSK_PIPE0); gen_fsk_packet_format_set(GEN_FSK_PACKET_FORMAT_FIXED_PAYLOAD,APP_PAYLOAD_LEN); gen_fsk_radio_power_set(GEN_FSK_RADIO_POWER_0DBM);复制 B数据包填充 gen_fs

  • 致小白:详解调幅收音机的原理 #妈妈再也不用担心我不懂收音机啦!

    标题:致小白:详解调幅收音机的原理#妈妈再也不用担心我不懂收音机啦! 作者:Pleiades_Antares 出品:BDF元培调查组-北京市内包小组 版权声明:本作系完全原创,他人不得在原作者不知情或不同意的条件下私自转载,欢迎转发。部分图片来源于网络,侵删 (后期会出收音机制作手册的电子版,喜欢的可以自己去打印,本文仅介绍调幅收音机的原理,其组装、调试以及焊接的全方位指导请参阅《小白手册》) (原作品为精修小册子+论文,文字精简,请仔细阅读嗷) 收音机的介绍 收音机,是一种由机械器件、电子器件、磁铁等构造而成,用电能将电波信号转换并能收听广播电台发射音频信号的机器。自1904年收音机被发明后,无线电广播成为一种主要的信息传播和宣传方式。它作为无线电传媒的鼻祖,虽然之后又发明了电视等其它媒体,但是直到今天它仍是一种不可或缺的传媒方式,广泛的存在于我们的生活之中。 收音机的原理 广播电台始于20世纪初,最早用于小部分科技迷之间的娱乐,后转为针对大众的新闻传播媒介和娱乐方式。它传播区域广,覆盖面积大。通过广播电台,人们可以听到百里之外甚至千里之外的声音。 目前使用最广泛的广播主要为调幅广播

  • 解决“NOT FOUND The requested URL was not found on this server”

    官网突然只能打开首页再点击其他所有链接都报404错误(NOTFOUND TherequestedURLwasnotfoundonthisserver)一开始认为是服务器配置出了问题 于是开始搞配置文件 重启apache  甚至重启服务器 但都于事无补 最后突然看到一篇文章说是网站少了 重写文件.htacces这个文件之后会发生这种情况,然后我去网站根目录去查看 果然少了.htacces这个文件 从本地上传上来之后 问题迎刃而解了 <IfModulemod_rewrite.c> <IfModulemod_negotiation.c> Options-MultiViews </IfModule> RewriteEngineOn #RedirectTrailingSlashesIfNotAFolder... RewriteCond%{REQUEST_FILENAME}!-d RewriteRule^(.*)/$/$1[L,R=301] #Handle

  • Python“快速复制粘贴”ins数据,一个简单的外国分享网站

    序言 Instagram(照片墙)是一款运行在移动端上的社交应用,以一种快速、美妙和有趣的方式将你随时抓拍下的图片彼此分享,Facebook公司旗下社交应用 本篇文章主要是如何“高速复制粘贴”Instagram里的视频 环境使用 Python3.8 Pycharm 主要模块使用 requests 代码编写 请求网站 url='https://www.instagram.com/graphql/query/?query_hash=69cba40317214236af40e7efa697781d&variables=%7B%22id%22%3A%2225025320%22%2C%22first%22%3A12%2C%22after%22%3A%22QVFDNFFmNWtjVWptaHNHN2Fhd21hdlFOQ1BMbDZQeHMzSVczMnl6T2dUN2U3YU5kYm9jZW1rYXgtUHlyQ0xMS2tjRm9iLXp2WG5Zb2NWSE9LR3laRU9zTw%3D%3D%22%7D' headers={ 'cooki

  • Leftmost Ball

    题目链接:Clickhere Solution: 我们把问题转化一下,改成可以放白球和其他颜色的球 那么对于一种合法的方案,显然有它的任意一个前缀的白球数大于等于其他颜色数 那么,我们考虑设\(f[i][j]\)表示已经放了\(i\)个白球,刚好放完了\(j\)种颜色的方案数 考虑有两种转移,一种是我们再放一个白球,或者再加入一种颜色 这里我们钦定接下来放的第一个球一定在第一个空缺的位置,否则就会算重 那么转移就是这样的: \[f[i][j]=f[i-1][j]+f[i][j-1]\times{(k-1)\times(n-j+1)+n-i-1\choosek-2} \]需要注意的是,当\(k=1\)时,我们需要给出特判,并且我们在\(dp\)时是没有考虑颜色的排列顺序的,所以最后要乘上阶乘 Code: #include<bits/stdc++.h> #defineintlonglong usingnamespacestd; constintN=2e3+11; constintM=4e6+11; constintmod=1e9+7; intn,k,f[N][N],fac[M]

  • [LeetCode]Palindrome Number

    题意:又是回文判断:该数是否是回文数 原题来自:https://leetcode.com/problems/palindrome-number/ 分析:回文真多,直接把数反转来判断是否相等。 1classSolution{ 2public: 3boolisPalindrome(intx){ 4inttemp=x; 5longlongres=0; 6 7if(x<0) 8{ 9returnfalse; 10} 11 12while(temp>0) 13{ 14res=res*10+temp%10; 15temp=temp/10; 16} 17 18return(res==x)?true:false; 19} 20};复制   作者:orange1438 出处:http://www.cnblogs.com/orange1438/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。复制  

  • Dubbo封装rest服务返回结果

    由于Dubbo服务考虑到一个是给其他系统通过RPC调用,另外一个是提供HTTP协议本身系统的后台管理页面,因此Dubbo返回参数在rest返回的时候配置拦截器进行处理。 在拦截器中,对返回参数封装成如下对象,并统一输出到前端。 1packagecom.wjs.common.web; 2 3importorg.apache.commons.lang.builder.ReflectionToStringBuilder; 4 5/** 6*服务返回给客户端的json对象包装 7*/ 8publicclassJsonResult<T>{ 9 10privatebooleansuccess=false; 11 12privateStringresultMsg=""; 13 14privateTdata=null; 15 16publicJsonResult(booleanstatus,StringresultMsg){ 17this.success=status; 18this.resultMsg=resultMsg; 19} 20 21publicJsonResult(bool

  • 自定义包的目录结构、go install 和 go test

    为了示范,我们创建了一个名为uc的简单包,它含有一个UpperCase函数将字符串的所有字母转换为大写。当然这并不值得创建一个自己包,同样的功能已被包含在strings包里,但是同样的技术也可以应用在更复杂的包中。 自定义包的目录结构   下面的结构给了你一个好的示范: /home/user/goprograms ucmain.go(uc包主程序) Makefile(ucmain的makefile) ucmain src/uc(包含uc包的go源码) uc.go uc_test.go Makefile(包的makefile) uc.a _obj uc.a _test uc.a bin(包含最终的执行文件) ucmain pkg/linux_amd64 uc.a(包的目标文件) 复制   将你的项目放在goprograms目录下(你可以创建一个环境变量GOPATH:在.profile和.bashrc文件中添加exportGOPATH=/home/user/goprograms),而你的项目将作为src的子目录。uc包中的功能在uc.go中实现。 packageuc import"stri

  • UVa11069:A Graph Problem

    UVa11069:AGraphProblem 题目大意 给定n个配成一列的节点,标号从1到n。现在要求出满足下列两个条件的子集的数量。 子集中的节点不能相邻 在不破坏条件1的前提下,不可能进一步增加节点。 Solution 这是一道动态规划题目,直接上公式吧。 dp[0]=0 dp[1]=dp[2]=1 dp[x]=dp[x-2]+dp[x-3](x>=3) 为了满足条件1和条件2,相邻的两个节点只能相隔一个节点或两个节点。 为了方便计算,我加入了编号为0的虚拟节点。 最后的答案是dp[n]+dp[n-1] AC-Code(C++) Time:0ms #include<iostream> #include<iomanip> #include<algorithm> #include<string> #include<cstring> #include<map> #include<set> #include<vector> #include<cmath> #in

相关推荐

推荐阅读