Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

leetcode: 93. Restore IP Addresses

$
0
0

Q

Given a string containing only digits, restore it by returning all possible valid IP address combinations.

For example:
Given “25525511135”,

return [“255.255.11.135”, “255.255.111.35”]. (Order does not matter)

AC

class Solution(object):
    def restoreIpAddresses(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        ans = []
        self.helper(ans, s, 4, [])
        return ['.'.join(x) for x in ans]

    def helper(self, ans, s, k, temp):
        if len(s) > k*3:
            return
        if k == 0:
            ans.append(temp[:])
        else:
            for i in range(min(3,len(s)-k+1)):
                if i==2 and int(s[:3]) > 255 or i > 0 and s[0] == '0':
                    continue
                self.helper(ans, s[i+1:], k-1, temp+[s[:i+1]])


# Time:  O(n^m) = O(3^4)
# Space: O(n * m) = O(3 * 4)
class Solution2(object):
    def restoreIpAddresses(self, s):
        result = []
        self.restoreIpAddressesRecur(result, s, 0, "", 0)
        return result

    def restoreIpAddressesRecur(self, result, s, start, current, dots):
        # pruning to improve performance
        if (4 - dots) * 3 < len(s) - start or (4 - dots) > len(s) - start:
            return
        if start == len(s) and dots == 4:
            result.append(current[:-1])
        else:
            for i in xrange(start, start + 3):
                if len(s) > i and self.isValid(s[start:i + 1]):
                    current += s[start:i + 1] + '.'
                    self.restoreIpAddressesRecur(result, s, i + 1, current, dots + 1)
                    current = current[:-(i - start + 2)]

    def isValid(self, s):
        if len(s) == 0 or (s[0] == '0' and s != "0"):
            return False
        return int(s) < 256


if __name__ == "__main__":
    assert Solution().restoreIpAddresses("0000") == ['0.0.0.0']


作者:JNingWei 发表于2017/11/22 10:22:46 原文链接
阅读:0 评论:0 查看评论

leetcode: 94. Binary Tree Inorder Traversal

$
0
0

Q

Given a binary tree, return the inorder traversal of its nodes’ values.

For example:
Given binary tree [1,null,2,3],

   1
    \
     2
    /
   3

return [1,3,2].

Note: Recursive solution is trivial, could you do it iteratively?

AC

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res = []
        self.helper(root, res)
        return res

    def helper(self, root, res):
        if root:
            self.helper(root.left, res)
            res.append(root.val)
            self.helper(root.right, res)


# Time:  O(n)
# Space: O(1)
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

# Morris Traversal Solution
class Solution2(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result, curr = [], root
        while curr:
            if curr.left is None:
                result.append(curr.val)
                curr = curr.right
            else:
                node = curr.left
                while node.right and node.right != curr:
                    node = node.right
                if node.right is None:
                    node.right = curr
                    curr = curr.left
                else:
                    result.append(curr.val)
                    node.right = None
                    curr = curr.right
        return result


# Time:  O(n)
# Space: O(h)
# Stack Solution
class Solution3(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result, stack = [], [(root, False)]
        while stack:
            root, is_visited = stack.pop()
            if root is None:
                continue
            if is_visited:
                result.append(root.val)
            else:
                stack.append((root.right, False))
                stack.append((root, True))
                stack.append((root.left, False))
        return result


if __name__ == "__main__":
    root, root.right, root.right.left = TreeNode(1), TreeNode(2), TreeNode(3)
    assert Solution().inorderTraversal(root) == [1, 3, 2]


作者:JNingWei 发表于2017/11/22 10:23:17 原文链接
阅读:0 评论:0 查看评论

leetcode: 95. Unique Binary Search Trees II

$
0
0

Q

Given an integer n, generate all structurally unique BST’s (binary search trees) that store values 1…n.

For example,
Given n = 3, your program should return all 5 unique BST’s shown below.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

AC

# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def generateTrees(self, n):
        """
        :type n: int
        :rtype: List[TreeNode]
        """
        return self.buildTree(0, n)

    def buildTree(self, n1, n2):
        if n1==n2:
            return [None]
        if n1+1 == n2:
            node = TreeNode(n1+1)
            node.left = None
            node.right = None
            return [node]
        else:
            results = []
            for x in range(n1, n2):
                left_list = self.buildTree(n1, x)
                right_list = self.buildTree(x+1, n2)
                for left in left_list:
                    for right in right_list:
                        node = TreeNode(x+1)
                        node.left = left
                        node.right = right
                        results.append(node)
            return results


# Time:  O(4^n / n^(3/2)) ~= Catalan numbers
# Space: O(4^n / n^(3/2)) ~= Catalan numbers
# Definition for a  binary tree node
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

    def __repr__(self):
        if self:
            serial = []
            queue = [self]
            while queue:
                cur = queue[0]
                if cur:
                    serial.append(cur.val)
                    queue.append(cur.left)
                    queue.append(cur.right)
                else:
                    serial.append("#")
                queue = queue[1:]
            while serial[-1] == "#":
                serial.pop()
            return repr(serial)
        else:
            return None

class Solution2(object):
    def generateTrees(self, n):
        return self.generateTreesRecu(1, n)

    def generateTreesRecu(self, low, high):
        result = []
        if low > high:
            result.append(None)
        for i in xrange(low, high + 1):
            left = self.generateTreesRecu(low, i - 1)
            right = self.generateTreesRecu(i + 1, high)
            for j in left:
                for k in right:
                    cur = TreeNode(i)
                    cur.left = j
                    cur.right = k
                    result.append(cur)
        return result


if __name__ == "__main__":
    print Solution().generateTrees(3)


作者:JNingWei 发表于2017/11/22 10:23:49 原文链接
阅读:0 评论:0 查看评论

leetcode: 96. Unique Binary Search Trees

$
0
0

Q

Given n, how many structurally unique BST’s (binary search trees) that store values 1…n?

For example,
Given n = 3, there are a total of 5 unique BST’s.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

AC

class Solution(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==0:return 1
        if n==1:return 1
        if n==2:return 2
        if n==3:return 5
        self.map = {0:1, 1:1, 2:2, 3:5}
        return self._getnum(n)

    def _getnum(self, n):
        if n in self.map:
            return self.map[n]
        total = 0
        for i in range(n):
            left = self._getnum(i)
            right = self._getnum(n-i-1)
            total += left*right
        self.map[n] = total
        return total


# Time:  O(n)
# Space: O(1)
# Math solution.
class Solution2(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 0:
            return 1
        def combination(n, k):
            count = 1
            for i in xrange(1, k + 1):
                count = count * (n - i + 1) / i;
            return count
        return combination(2 * n, n) - combination(2 * n, n - 1)


# Time:  O(n^2)
# Space: O(n)
# DP solution.
class Solution3(object):
    def numTrees(self, n):
        counts = [1, 1]
        for i in xrange(2, n + 1):
            count = 0
            for j in xrange(i):
                count += counts[j] * counts[i - j - 1]
            counts.append(count)
        return counts[-1]


if __name__ == "__main__":
    assert Solution().numTrees(3) == 5


作者:JNingWei 发表于2017/11/22 10:24:24 原文链接
阅读:0 评论:0 查看评论

leetcode: 97. Interleaving String

$
0
0

Q

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

For example,
Given:
s1 = “aabcc”,
s2 = “dbbca”,

When s3 = “aadbbcbcac”, return true.
When s3 = “aadbbbaccc”, return false.

AC

class Solution(object):
    def isInterleave(self, s1, s2, s3):
        """
        :type s1: str
        :type s2: str
        :type s3: str
        :rtype: bool
        """
        r, c, l= len(s1), len(s2), len(s3)
        if r+c != l:
            return False
        stack, visited = [(0, 0)], set((0, 0))
        while stack:
            x, y = stack.pop()
            if x+y == l:
                return True
            if x+1 <= r and s1[x] == s3[x+y] and (x+1, y) not in visited:
                stack.append((x+1, y)); visited.add((x+1, y))
            if y+1 <= c and s2[y] == s3[x+y] and (x, y+1) not in visited:
                stack.append((x, y+1)); visited.add((x, y+1))
        return False


# Time:  O(m * n)
# Space: O(m + n)
# Dynamic Programming + Sliding Window
class Solution2(object):
    def isInterleave(self, s1, s2, s3):
        if len(s1) + len(s2) != len(s3):
            return False
        if len(s1) > len(s2):
            return self.isInterleave(s2, s1, s3)
        match = [False for i in xrange(len(s1) + 1)]
        match[0] = True
        for i in xrange(1, len(s1) + 1):
            match[i] = match[i -1] and s1[i - 1] == s3[i - 1]
        for j in xrange(1, len(s2) + 1):
            match[0] = match[0] and s2[j - 1] == s3[j - 1]
            for i in xrange(1, len(s1) + 1):
                match[i] = (match[i - 1] and s1[i - 1] == s3[i + j - 1]) \
                           or (match[i] and s2[j - 1] == s3[i + j - 1])
        return match[-1]


# Time:  O(m * n)
# Space: O(m * n)
# Dynamic Programming
class Solution3(object):
    def isInterleave(self, s1, s2, s3):
        if len(s1) + len(s2) != len(s3):
            return False
        match = [[False for i in xrange(len(s2) + 1)] for j in xrange(len(s1) + 1)]
        match[0][0] = True
        for i in xrange(1, len(s1) + 1):
            match[i][0] = match[i - 1][0] and s1[i - 1] == s3[i - 1]
        for j in xrange(1, len(s2) + 1):
            match[0][j] = match[0][j - 1] and s2[j - 1] == s3[j - 1]
        for i in xrange(1, len(s1) + 1):
            for j in xrange(1, len(s2) + 1):
                match[i][j] = (match[i - 1][j] and s1[i - 1] == s3[i + j - 1]) \
                              or (match[i][j - 1] and s2[j - 1] == s3[i + j - 1])
        return match[-1][-1]


# Time:  O(m * n)
# Space: O(m * n)
# Recursive + Hash
class Solution4(object):
    def isInterleave(self, s1, s2, s3):
        self.match = {}
        if len(s1) + len(s2) != len(s3):
            return False
        return self.isInterleaveRecu(s1, s2, s3, 0, 0, 0)

    def isInterleaveRecu(self, s1, s2, s3, a, b, c):
        if repr([a, b]) in self.match.keys():
            return self.match[repr([a, b])]
        if c == len(s3):
            return True
        result = False
        if a < len(s1) and s1[a] == s3[c]:
            result = result or self.isInterleaveRecu(s1, s2, s3, a + 1, b, c + 1)
        if b < len(s2) and s2[b] == s3[c]:
            result = result or self.isInterleaveRecu(s1, s2, s3, a, b + 1, c + 1)
        self.match[repr([a, b])] = result
        return result


if __name__ == "__main__":
    assert Solution().isInterleave("a", "", "a") == True
    assert Solution().isInterleave("aabcc", "dbbca", "aadbbcbcac") == True
    assert Solution().isInterleave("aabcc", "dbbca", "aadbbbaccc") == False


作者:JNingWei 发表于2017/11/22 10:25:05 原文链接
阅读:0 评论:0 查看评论

Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术

$
0
0

Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术

参考书籍:《Unity Shader 入门精要》


Unity Shader的内置变量


纹理动画

可用于代替粒子系统模拟动画效果。

帧序列动画

8x8帧序列纹理动画

Properties {
    _Color ("Color Tint", Color) = (1, 1, 1, 1)
    _MainTex ("Image Sequence", 2D) = "white" {}            // 包含所有关键帧图像的纹理
    _HorizontalAmount ("Horizontal Amount", Float) = 4      // 水平方向包含关键帧图像个数
    _VerticalAmount ("Vertical Amount", Float) = 4          // 同上(竖直方向)
    _Speed ("Speed", Range(1, 100)) = 30                    // 播放速度
}

因为序列帧图像通常是透明纹理,所以就按半透明的方式设置。

// 序列帧图像通常包含透明通道
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}

Pass {
    Tags { "LightMode"="ForwardBase" }

    // 关闭深度写入,开启混合模式
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha

    ...

    fixed4 frag (v2f i) : SV_Target {
        float time = floor(_Time.y * _Speed);               // floor()取整。CG的函数
        float row = floor(time / _HorizontalAmount);        // 行索引
        float column = time % _HorizontalAmount;        // 列索引

        // 纹理坐标从上到下,所以是-row。下面两种计算方法
        //half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount);
        //uv.x += column / _HorizontalAmount;
        //uv.y -= row / _VerticalAmount;        

        half2 uv = i.uv + half2(column, -row);
        uv.x /=  _HorizontalAmount;
        uv.y /= _VerticalAmount;

        fixed4 c = tex2D(_MainTex, uv);
        c.rgb *= _Color;

        return c;
    }
}

滚动动画

可以模拟2D跑酷游戏背景的视察效果。

Properties {
    _MainTex ("Base Layer (RGB)", 2D) = "white" {}          // 第一层背景(较远背景)
    _DetailTex ("2nd Layer (RGB)", 2D) = "white" {}         // 较近背景
    _ScrollX ("Base layer Scroll Speed", Float) = 1.0       // 第一层背景滚动速度
    _Scroll2X ("2nd layer Scroll Speed", Float) = 1.0       // 第二层速度
    _Multiplier ("Layer Multiplier", Float) = 1             // 纹理亮度
}
v2f vert (a2v v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);

    // TRANSFORM_TEX 得到初始纹理坐标,加上偏移坐标。frac为获取小数部分的值。
    o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y);
    o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);

    return o;
}

fixed4 frag (v2f i) : SV_Target {
    fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
    fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);

    fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
    c.rgb *= _Multiplier;

    return c;
}

顶点动画

即修改顶点信息的动画。

一张长方形纹理,通过修改顶点信息,实现扭曲效果。

Properties {
    _MainTex ("Main Tex", 2D) = "white" {}
    _Color ("Color Tint", Color) = (1, 1, 1, 1)
    _Magnitude ("Distortion Magnitude", Float) = 1                  // 幅度
    _Frequency ("Distortion Frequency", Float) = 1                  // 频率
    _InvWaveLength ("Distortion Inverse Wave Length", Float) = 10   // 波长的倒数
    _Speed ("Speed", Float) = 0.5
}
// DisableBatching:取消批处理。需要对模型空间下的顶点位置进行偏移,所以就不合并模型。
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}

Pass {
    Tags { "LightMode"="ForwardBase" }

    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off                            // 关闭剔除模式(正反面都显示)

    ...

    v2f vert(a2v v) {
        v2f o;

        float4 offset;
        offset.yzw = float3(0.0, 0.0, 0.0);
        // 只改变X变量
        offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
        o.pos = UnityObjectToClipPos(v.vertex + offset);

        o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
        o.uv +=  float2(0.0, _Time.y * _Speed);

        return o;
    }

}


注意到前面使用内置阴影的Pass是没有处理顶点动画的,所以最后投影的阴影是错误的,需要自定义ShadowCasterPass,在这个Pass做相同顶点变换即可。

下面用到阴影的宏都在UnityCG.cginc中定义。

Pass {
    Tags { "LightMode" = "ShadowCaster" }

    ...

    #pragma multi_compile_shadowcaster

    ...

    struct v2f { 
        // 内置宏,阴影投射需要的变量
        V2F_SHADOW_CASTER;
    };

    v2f vert(appdata_base v) {
        v2f o;

        float4 offset;
        offset.yzw = float3(0.0, 0.0, 0.0);
        offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
        v.vertex = v.vertex + offset;

        // 计算阴影
        TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)

        return o;
    }

    fixed4 frag(v2f i) : SV_Target {
        // 阴影投射
        SHADOW_CASTER_FRAGMENT(i)
    }
    ENDCG
}

广告牌技术(Billboarding)

即让纹理始终面对着镜头。本质就是构建旋转矩阵,三个基向量:表面法线、向上的方向、向右的方向。还需要指定一个锚点,即旋转中心。

计算方法(如下图):
1. 先计算向右方向 right = up × normal。起始up是竖直向上的。
2. 叉乘即可得到向上方向 up’ = normal × right。

Vertical Restraints值为1,所有星星不管原来什么角度都会转向到镜头。

Vertical Restraints值为0,所有星星固定向上方向,并最大限度面向镜头。

Properties {
    _MainTex ("Main Tex", 2D) = "white" {}
    _Color ("Color Tint", Color) = (1, 1, 1, 1)
    _VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1      // 垂直程度,0:固定向上,1:固定法线
}
// 需要模型空间下的位置来作为锚点计算,所以要关掉批处理。
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}

Pass { 
    Tags { "LightMode"="ForwardBase" }

    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off

    CGPROGRAM

    ...

    v2f vert (a2v v) {
        v2f o;

        float3 center = float3(0, 0, 0);                // 模型空间的原点作为广告牌锚点
        float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));   // 获取模型空间下视角

        float3 normalDir = viewer - center;
        // _VerticalBillboarding 为1为法线固定(始终向上),为0为向上方向固定。 
        normalDir.y =normalDir.y * _VerticalBillboarding;
        normalDir = normalize(normalDir);
        // 通过normalDir.y 先判断法线和向上是否平行(叉积会错),来改变向上方向
        float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
        float3 rightDir = normalize(cross(upDir, normalDir));
        upDir = normalize(cross(normalDir, rightDir));  

        // 通过三个正交基矢量,计算得到新的顶点位置
        float3 centerOffs = v.vertex.xyz - center;
        float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;

        o.pos = UnityObjectToClipPos(float4(localPos, 1));      // 模型转裁剪空间
        o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

        return o;
    }

关于 DisableBatching

如果要进行一些顶点动画,就要关闭批处理。性能会下降,所以尽量避免使用模型空间下的绝对位置和方向进行计算。如广告拍技术中,可以用顶点颜色来存储顶点到锚点的距离。

作者:l773575310 发表于2017/11/21 22:55:14 原文链接
阅读:1 评论:0 查看评论

Go实战--golang中使用echo框架中的HTTP/2、Server Push(labstack/echo、golang.org/x/net/http2)

$
0
0

生命不止,继续 go go go !!!

继续echo web框架,今天搞一下http2。

HTTP2

What is HTTP/2?
HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol.

The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.

新的二进制格式(Binary Format)
HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

多路复用(MultiPlexing)
即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。多路复用原理图:

header压缩
HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

服务端推送(server push)
同SPDY一样,HTTP2.0也具有server push功能。

生成证书

go run C:\go\src\crypto\tls\generate_cert.go --host localhost
2017/11/22 10:06:58 written cert.pem
2017/11/22 10 :06:58 written key.pem

echo中的HTTP/2

代码main.go:

package main

import (
    "fmt"
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.GET("/request", func(c echo.Context) error {
        req := c.Request()
        format := `
            <code>
                Protocol: %s<br>
                Host: %s<br>
                Remote Address: %s<br>
                Method: %s<br>
                Path: %s<br>
            </code>
        `
        return c.HTML(http.StatusOK, fmt.Sprintf(format, req.Proto, req.Host, req.RemoteAddr, req.Method, req.URL.Path))
    })
    e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
}

浏览器输入:
https://localhost:1323/request

结果:

Protocol: HTTP/2.0
Host: localhost:1323
Remote Address: [::1]:1905
Method: GET
Path: /request

如果出现错误:
http: TLS handshake error from [::1]:1735: tls: first record does not look like a TLS handshake.

请检查是否输入的是https

golang.org/x/net/http2

文档地址:
https://godoc.org/golang.org/x/net/http2

获取:
get golang.org/x/net/http2

代码main.go:

package main

import (
    "fmt"
    "html"
    "log"
    "net/http"

    "golang.org/x/net/http2"
)

func main() {
    var srv http.Server
    http2.VerboseLogs = true
    srv.Addr = ":8080"
    // This enables http2 support
    http2.ConfigureServer(&srv, nil)

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi tester %q\n", html.EscapeString(r.URL.Path))
        ShowRequestInfoHandler(w, r)
    })
    // Listen as https ssl server
    // NOTE: WITHOUT SSL IT WONT WORK!!
    log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
}
func ShowRequestInfoHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    fmt.Fprintf(w, "Method: %s\n", r.Method)
    fmt.Fprintf(w, "Protocol: %s\n", r.Proto)
    fmt.Fprintf(w, "Host: %s\n", r.Host)
    fmt.Fprintf(w, "RemoteAddr: %s\n", r.RemoteAddr)
    fmt.Fprintf(w, "RequestURI: %q\n", r.RequestURI)
    fmt.Fprintf(w, "URL: %#v\n", r.URL)
    fmt.Fprintf(w, "Body.ContentLength: %d (-1 means unknown)\n", r.ContentLength)
    fmt.Fprintf(w, "Close: %v (relevant for HTTP/1 only)\n", r.Close)
    fmt.Fprintf(w, "TLS: %#v\n", r.TLS)
    fmt.Fprintf(w, "\nHeaders:\n")
    r.Header.Write(w)
}

浏览器输入:
https://localhost:8080/

结果:

Hi tester "/"
Method: GET
Protocol: HTTP/2.0
Host: localhost:8080
RemoteAddr: [::1]:2750
RequestURI: "/"
URL: &url.URL{Scheme:"", Opaque:"", User:(*url.Userinfo)(nil), Host:"", Path:"/", RawPath:"", ForceQuery:false, RawQuery:"", Fragment:""}
Body.ContentLength: 0 (-1 means unknown)
Close: false (relevant for HTTP/1 only)
TLS: &tls.ConnectionState{Version:0x303, HandshakeComplete:true, DidResume:false, CipherSuite:0xc02f, NegotiatedProtocol:"h2", NegotiatedProtocolIsMutual:true, ServerName:"localhost", PeerCertificates:[]*x509.Certificate(nil), VerifiedChains:[][]*x509.Certificate(nil), SignedCertificateTimestamps:[][]uint8(nil), OCSPResponse:[]uint8(nil), TLSUnique:[]uint8{0xa6, 0x3c, 0xfe, 0x93, 0x3c, 0x15, 0x4f, 0x74, 0xfc, 0x97, 0xca, 0x73}}

Headers:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Alexatoolbar-Alx_ns_ph: AlexaToolbar/alx-4.0
Cookie: _ga=GA1.1.981224509.1509938615
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36

Server Push

Server Push是什么

简单来讲就是当用户的浏览器和服务器在建立链接后,服务器主动将一些资源推送给浏览器并缓存起来,这样当浏览器接下来请求这些资源时就直接从缓存中读取,不会在从服务器上拉了,提升了速率。举一个例子就是:
假如一个页面有3个资源文件index.html,index.css,index.js,当浏览器请求index.html的时候,服务器不仅返回index.html的内容,同时将index.css和index.js的内容push给浏览器,当浏览器下次请求这2两个文件时就可以直接从缓存中读取了。

Server Push原理是什么

要想了解server push原理,首先要理解一些概念。我们知道HTTP2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧主要分成这几种类型:

HEADERS frame(请求返回头帧):这种帧主要携带的http请求头信息,和HTTP1的header类似。

DATA frames(数据帧) :这种帧存放真正的数据content,用来传输。
PUSH_PROMISE frame(推送帧):这种帧是由server端发送给client的帧,用来表示server push的帧,这种帧是实现server push的主要帧类型。

RST_STREAM(取消推送帧):这种帧表示请求关闭帧,简单讲就是当client不想接受某些资源或者接受timeout时会向发送方发送此帧,和PUSH_PROMISE frame一起使用时表示拒绝或者关闭server push。

了解了相关的帧类型,下面就是具体server push的实现过程了:
由多路复用我们可以知道HTTP2中对于同一个域名的请求会使用一条tcp链接而用不同的stream ID来区分各自的请求。
当client使用stream 1请求index.html时,server正常处理index.html的请求,并可以得知index.html页面还将要会请求index.css和index.js。
server使用stream 1发送PUSH_PROMISE frame给client告诉client我这边可以使用stream 2来推送index.js和stream 3来推送index.css资源。
server使用stream 1正常的发送HEADERS frame和DATA frames将index.html的内容返回给client。
client接收到PUSH_PROMISE frame得知stream 2和stream 3来接收推送资源。
server拿到index.css和index.js便会发送HEADERS frame和DATA frames将资源发送给client。
client拿到push的资源后会缓存起来当请求这个资源时会从直接从从缓存中读取。

Golang1.8中的Server Push

代码main.go:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

var image []byte

// preparing image
func init() {
    var err error
    image, err = ioutil.ReadFile("./image.png")
    if err != nil {
        panic(err)
    }
}

// Send HTML and push image
func handlerHtml(w http.ResponseWriter, r *http.Request) {
    pusher, ok := w.(http.Pusher)
    if ok {
        fmt.Println("Push /image")
        pusher.Push("/image", nil)
    }
    w.Header().Add("Content-Type", "text/html")
    fmt.Fprintf(w, `<html><body><img src="/image"></body></html>`)
}

// Send image as usual HTTP request
func handlerImage(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "image/png")
    w.Write(image)
}
func main() {
    http.HandleFunc("/", handlerHtml)
    http.HandleFunc("/image", handlerImage)
    fmt.Println("start http listening :18443")
    err := http.ListenAndServeTLS(":18443", "server.crt", "server.key", nil)
    fmt.Println(err)
}

浏览器输入:
https://localhost:18443/

可以使用插件HTTP/2 and SPDY indicator
chrome://net-internals/#http2

echo框架中的Server Push

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>HTTP/2 Server Push</title>
  <link rel="stylesheet" href="/app.css">
  <script src="/app.js"></script>
</head>
<body>
  <img class="echo" src="/echo.png">
  <h2>The following static files are served via HTTP/2 server push</h2>
  <ul>
    <li><code>/app.css</code></li>
    <li><code>/app.js</code></li>
    <li><code>/echo.png</code></li>
  </ul>
</body>
</html>

main.go

package main

import (
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.Static("/", "static")
    e.GET("/", func(c echo.Context) (err error) {
        pusher, ok := c.Response().Writer.(http.Pusher)
        if ok {
            if err = pusher.Push("/app.css", nil); err != nil {
                return
            }
            if err = pusher.Push("/app.js", nil); err != nil {
                return
            }
            if err = pusher.Push("/echo.png", nil); err != nil {
                return
            }
        }
        return c.File("index.html")
    })
    e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
}

浏览器输入:
https://localhost:1323/

参考:
http://www.alloyteam.com/2017/01/http2-server-push-research/

这里写图片描述

作者:wangshubo1989 发表于2017/11/22 14:07:00 原文链接
阅读:1145 评论:0 查看评论

leetcode题解-8. String to Integer (atoi) && 468. Validate IP Address

$
0
0

今天开始刷String部分中等难度的题目,先看第一道

Implement atoi to convert a string to an integer.

Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.

Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.

Update (2015-02-10):
The signature of the C++ function had been updated. If you still see your function signature accepts a const char * argument, please click the reload button  to reset your code definition.

将字符串转化为int型整数,其实主要有两点需要考虑一个是数的正负号,另一个是溢出问题,此外在判断每一个字符是否为数字即可,可以写出下面的代码:

    //45%
    public static int myAtoi(String str) {
        if (str == null || str.length() == 0)
            return 0;//
        str = str.trim();
        char firstChar = str.charAt(0);
        //sign用于表示数字的正负号,start表示当前向后遍历的索引位置
        int sign = 1, start = 0, len = str.length();
        long sum = 0;
        if (firstChar == '+') {
            sign = 1;
            start++;
        } else if (firstChar == '-') {
            sign = -1;
            start++;
        }
        for (int i = start; i < len; i++) {
            if (!Character.isDigit(str.charAt(i)))
                return (int) sum * sign;
            sum = sum * 10 + str.charAt(i) - '0';
            //判断是否溢出
            if (sign == 1 && sum > Integer.MAX_VALUE)
                return Integer.MAX_VALUE;
            if (sign == -1 && (-1) * sum < Integer.MIN_VALUE)
                return Integer.MIN_VALUE;
        }

        return (int) sum * sign;
    }

上面这段代码可以击败45%的用户,我们可以通过下面的方法来提升效率进而即便72%的用户。代码如下所示:

    //72%
    public int myAtoi1(String str) {
        str = str.trim();
        if (str.isEmpty())
            return 0;
        int sign = 1; int i = 0;
        if (str.charAt(0) == '-' || str.charAt(0) == '+'){
            sign = (str.charAt(0) == '-')? -1 : 1;
            if (str.length() < 2 || !Character.isDigit(str.charAt(1))) {
                return 0;
            }
            i++;
        }
        int n = 0;
        while (i < str.length()) {
            if (Character.isDigit(str.charAt(i))) {
                int d = str.charAt(i) - '0';
                if (n > (Integer.MAX_VALUE - d) / 10) { //Detect the integer overflow.
                    n = (sign == -1)? Integer.MIN_VALUE : Integer.MAX_VALUE;
                    return n;
                }
                n = n*10 + d;
            } else {
                break;
            }
            i++;
        }
        return sign * n;
    }

接下来看第二道题目:

Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.

IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots ("."), e.g.,172.16.254.1;

Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is invalid.

IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (":"). For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper cases).

However, we don't replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address.

Besides, extra leading zeros in the IPv6 is also invalid. For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid.

Note: You may assume there is no extra space or special characters in the input string.

Example 1:
Input: "172.16.254.1"

Output: "IPv4"

Explanation: This is a valid IPv4 address, return "IPv4".
Example 2:
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334"

Output: "IPv6"

Explanation: This is a valid IPv6 address, return "IPv6".
Example 3:
Input: "256.256.256.256"

Output: "Neither"

Explanation: This is neither a IPv4 address nor a IPv6 address.

这道题目是判断一个给定的字符串是否为一个有效的IPV4或者IPV6地址,其实主要是一个字符串解析的方式,注意判断切分后的每个数字是否满足条件即可。自己多试几遍,把特例都试出来即可。主要有下面几个坑,第一如果字符串开始和结尾就是.或者:,那么切分的时候依然满足,所以要先把这种情况给排出,其次是将一个字符串转化为int型数时可能存在字母导致无法转换,这时我们加一个try catch语句来捕获异常即可。最后对于IPV6地址我们要对其中的每一个字符判断其是否符合条件。同样我们可以使用自己写判断来做,也可以使用一个正则表达式来判断,但是这种方法的效率比较低而已。两种方法的代码如下所示:

    //70%
    public static String validIPAddress(String IP) {
        if(IP.contains(".")){
            String [] nums = IP.split("\\.");
            if(IP.startsWith(".") || IP.endsWith(".") || nums.length != 4)
                return "Neither";
            for(String num : nums){
                if(num.startsWith("0") && !num.equals("0"))
                    return "Neither";
                try{
                    int parseInt = Integer.parseInt(num);
                    if(parseInt < 0 || parseInt > 255) return "Neither";
                    if(parseInt==0 && num.charAt(0)!='0') return "Neither";
                }catch (NumberFormatException nfe) {
                    return "Neither";
                }
            }
            return "IPv4";
        }else if(IP.contains(":")){
            String [] nums = IP.split(":");
            if(IP.startsWith(":") || IP.endsWith(":") || nums.length != 8)
                return "Neither";
            for(String num : nums){
                if(num.length() > 4 || num.equals(""))
                    return "Neither";
                char [] chars = num.toCharArray();
                for(char c : chars){
                    boolean isDigit = c>=48 && c<=57;
                    boolean isUppercaseAF = c>=65 && c<=70;
                    boolean isLowerCaseAF = c>=97 && c<=102;
                    if(!(isDigit || isUppercaseAF || isLowerCaseAF))
                        return "Neither";
                }
            }
            return "IPv6";
        }
        return "Neither";

    }

    //15%
    public String validIPAddress1(String IP) {
        if(IP.matches("(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"))return "IPv4";
        if(IP.matches("(([0-9a-fA-F]{1,4}):){7}([0-9a-fA-F]{1,4})"))return "IPv6";
        return "Neither";
    }
作者:liuchonge 发表于2017/11/22 14:08:28 原文链接
阅读:142 评论:0 查看评论

【蓝桥杯】【兰顿蚂蚁】

$
0
0

题目
兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种。
平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只“蚂蚁”。
蚂蚁的头部朝向为:上下左右其中一方。
蚂蚁的移动规则十分简单:
若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格;
若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,
蚂蚁经过漫长的混乱活动后,会开辟出一条规则的“高速公路”。
蚂蚁的路线是很难事先预测的。
你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第n步行走后所处的位置。
【数据格式】
输入数据的第一行是 m n 两个整数(3 < m, n < 100),表示正方形格子的行数和列数。
接下来是 m 行数据。
每行数据为 n 个被空格分开的数字。0 表示白格,1 表示黑格。
接下来是一行数据:x y s k, 其中x y为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从0开始编号)。
s 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:UDLR表示。k 表示蚂蚁走的步数。
输出数据为两个空格分开的整数 p q, 分别表示蚂蚁在k步后,所处格子的行号和列号。
例如, 输入:
5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5
程序应该输出:
1 3
再例如, 输入:
3 3
0 0 0
1 1 1
1 1 1
1 1 U 6
程序应该输出:
0 0
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

分析
题目貌似复杂,但是要耐心的理清楚题目的内容,按照题目的要求慢慢的解决,也会感觉到不复杂,最后用输入尝试看看输出是否一致。

源码

private static String ss = "URDL";
    private static int[][] a;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        a = new int[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                a[i][j] = sc.nextInt();
            }
        }

        int x = sc.nextInt();
        int y = sc.nextInt();
        char s = sc.next().charAt(0);
        int k = sc.nextInt();
        sc.close();


        walk(x, y, s, k);

    }

    private static void walk(int x, int y, char s, int k) {
        if(k == 0) {
            System.out.println(x + " " + y);
            return;
        }

        //获取新的方向,并把格子颜色变掉
        s =  getNext(s, x, y);

        switch (s) {
        case 'U':
            x -= 1;
            break;
        case 'R':
            y += 1;
            break;
        case 'D':
            x += 1;
            break;
        case 'L':
            y -= 1;
            break;

        }

        walk(x, y, s, k-1);


    }

    private static char getNext(char s, int x, int y) {
        int index = ss.indexOf(s);
        if(a[x][y] == 1) {
            //黑格,右转90度
            index++;
            if(index==ss.length()) {
                index = 0;
            }
            a[x][y] = 0;
        }else {
            //白格,左转90度
            index--;
            if(index == -1) {
                index = ss.length()-1;
            }
            a[x][y] = 1;
        }
        return ss.charAt(index);
    }

结果

5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5

1 3

作者:bear_huangzhen 发表于2017/11/22 14:38:50 原文链接
阅读:162 评论:0 查看评论

ACM比赛完了后怎么办

$
0
0

【来信】
尊敬的老师,您好!
  我是一个ACM竞赛选手,现在大三,在今年12月初的CCPC-FINAL结束后,我也差不多该走出这个ACM圈子了。
  对于接下来我该做什么,我真的好想有个方向,我感觉我大学第一次这么没有目标。
  说说我自己在考研面前,学业上普普通通,感觉和一本学生的数学(微积分,线性代数)肯定是比他们弱一点,但是我想也不排除我努力上来能超过他们。对于考研,我一开始打算的是如果没有找到好的实习公司去考研,但是我觉得这就像给自己留后路一样,我现在根本留不起,所以我打算的是打死也不考研,努力进入一家比较大的公司实习以及就业。
  我有一个普通二本的朋友,他能力比我强,体现在ACM解题能力(或者说智力/天赋),在我印象中,他在大三寒假以及大三下学期这段时间,看完了C++ primer、计算机网络还有一些书,自己照着STL源码打了STL源码,具体我也不知道,然后震惊的是他在暑假成功通过了百度的面试,前几个月也已经收到offer,成为了百度的正式员工。
  我很想进百度,想着大三暑假去百度实习。
  可惜我手上的资本很少,讽刺的就是一句自己眼高手低,竞赛资本仅仅只有ICPC铜,除了这个我想我现在什么都没有。那天我们的操作系统老师讲了他实验室这届毕业生的就业情况非常好,我被触动到了,我不是羡慕他们多好,我是在沮丧自己我的未来是不是很失败啊。我走在我们学校的跑道上想,我到底要做什么才能提升自己的实力啊。我需要为自己规划任务,可是我实在没有什么方向,恳请您的帮助。
  我请求您给我的建议,学习方向,学习内容,请不要觉得我只能做这么多来要求我,您说的我会努力去完成。
  感谢老师在百忙之中读完我这封信!感谢!

【回复】
  想起一句话:大一的不知道自己不知道,大二的知道自己不知道,大三的不知道自己知道,大四的知道自己知道。
  这样的说法不是对所有的大n生都适用。找我的人中,有很多,以迷茫为理由,一直停留在“知道自己不知道”的阶段。
而你,有ICPC铜在手,却如此的信心不足,真的是“不知道自己知道了什么”吗?
  你走的路,是学习计算机的一条很典型的路子。通过ACM训练,程序设计能力、算法能力、问题求解能力,这是最核心的能力。前几年开发APP开始火的时候,似乎有做应用的能力就可以了,而就看现在,人工智能的火爆,以算法为核心的能力再次地受到重视。这些能力不是轻易就可以上身的。
  考研和就业,没有谁是谁的后路的说法。无论选择哪一个,在一段时间之内,倾力而为,争取最大的可能即可。你要相信,在这两个方面,无论在哪个方向上着力,也都是正途。同时,选择一个方向,对另一个是有影响,或者意味着放弃,这是很正常的选择。殊途同归,不要在一个极短的时间范围之内考察,投入都不会白费。
  如何选择,你可以再考虑一下。
  顺着你的思路,其实,也看出你对除了ACM训练之外,这段时间需要自己找到信心。我就以目标为就业稍谈一些(其实,即使考研再上研,工作的事也是要考虑的)。
  这类的观点,我在下面几篇文章中谈过,你先看看。

从你现在的状况看,建议就是等期末考试完了后,找一个应用方向先去体验就行。有点像小马过河,你体会到的可能不像我说的这么容易,但也不是你想得那么难。还有,你往算法工程师的角度看一看,可能能有新的想法。
  若想争取百度实习的机会,搜索一下百度近期针对大学生的活动计划。该做什么,自然也就更有针对性了。还有其他企业呢!为此准备过了,这个过程就是最大的回报,足以保本了。
  还可以考察一下你校的一些实验室,是否还有进去的机会,有个氛围更好一些,你这样背景的同学,应该还是受欢迎的。
  你离毕业还有一年半,你的大学只处在1/2到5/8之间,还有3/8多一些,想想你已经有多大的改变吧!
  所以,对余下的时间可以让自己更好,你应该有信心的。

作者:sxhelijian 发表于2017/11/22 14:39:28 原文链接
阅读:171 评论:0 查看评论

leetcode题解-647. Palindromic Substrings

$
0
0

题目:

Given a string, your task is to count how many palindromic substrings in this string.

The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.

Example 1:
Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Note:
The input string length won't exceed 1000.

本题的目的是寻找一个字符串中存在的回文子串的个数,很容易想到的方法是挨个字符进行遍历,然后判断以他开始的子串是否为回文字符串,但是这种方法效率太低了,我们可以转变一下想法,那就是对每个字符,我们将其作为子串的中心,然后向两侧开始扩展判断是否为回文子串,这样效率就提升了很多,而且思路可以说是非常简单清晰了、下面看代码:

    int count = 0;

    public int countSubstrings(String s) {
        if (s == null || s.length() == 0) return 0;

        for (int i = 0; i < s.length(); i++) { // i is the mid point
            extendPalindrome(s, i, i); // odd length;
            extendPalindrome(s, i, i + 1); // even length
        }

        return count;
    }

    private void extendPalindrome(String s, int left, int right) {
        while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            count++; left--; right++;
        }
    }

此外我们还可以使用DP动态规划的方法进行求解,思路是使用一个二维数组来保存对应的两个元素是否相等,然后对dp数组的结果进行求和:

    public int countSubstrings1(String s) {
        int n = s.length();
        int res = 0;
        boolean[][] dp = new boolean[n][n];
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                dp[i][j] = s.charAt(i) == s.charAt(j) && (j - i < 3 || dp[i + 1][j - 1]);
                if(dp[i][j]) ++res;
            }
        }
        return res;
    }
作者:liuchonge 发表于2017/11/22 14:57:40 原文链接
阅读:132 评论:0 查看评论

详细的DedeCMS(织梦)目录权限安全设置教程

$
0
0
一、目录权限
根据统计,绝大部分网站的攻击都在根目录开始的,因此,栏目目录不能设置在根目录。
DEDECMS部署完成后,重点目录设置如下:
1)将install删除。
2) data、templets、uploads、a或html目录, 设置可读写,取消执行的权限(Windows如何设置目录的权限?);当然对于data文件夹还有更好的解决办法,那就是将data移出站点的根目录。
3) 如果网站下不需要专题的,必须删除 special 目录。如果需要的话,有网友是这样建议的:生成HTML后,备份special/index.php后将其删除,然后把这目录设置为可读写,不可执行的权限;但是,这样做比较麻烦,因为每次生成后就把需要将index.php文件删除,下次执行“生成”的时候又需要把他还原回来。
4) include、member、plus、后台管理目录设置为可执行脚本,可读,但不可写入(安装了附加模块的,book,ask,company,group 目录同样如此设置)。
二、其它需注意问题
1) 非万不得已的情况下,不要对网站直接使用MySQL root用户的权限,一般情况是,都是一个网站对应一个mysql用户,许可权限为:
SELECT, INSERT , UPDATE , DELETE
CREATE , DROP , INDEX , ALTER , CREATE TEMPORARY TABLES
由于DEDE并没有任何地方使用存储过程,因此务必禁用 FILE、EXECUTE 等执行存储过程或文件操作的权限。
三、经常留意dede的官方网站,及时打好dede补丁。


 


-----------------------------------------------下面是一些文件权限设置-------------------------------------------------------------


用户织梦建站,网站安全不可忽视。给大家分享织梦各目录的安全设置教程。以供参考。


/ 【站点上级目录】


假如要使用后台的目录相关的功能需求有列出目录的权限 //0444


/ 【站点根目录】


需求执行和读取权限 假如要在根目录下面创建文件和目录的话需求有写入权限 //0755


/install 【安装程序目录】


需求有执行和读取权限 //建议安装完成以后删除或者改名 //0555


/dede 【后台程序目录】


需求有执行权限和读取权限 //建议安装完成以后修正目录名称 //0755


/include 【主程序目录】


需求有写入、执行权限和读取权限 //0755 //建议在第一次安装后,去掉写入权限以及修正权限(需求重写配置文件时再暂时开启写入及修正权限)//0555


/member 【会员目录】


需求执行读取和权限 //建议去掉写入权限以及修正权限//0555


/plus 【插件目录】


需求有读取、写入和执行的权限 //建议在生成完站点地图和RSS文件后去掉写入权限以及修正权限 //0755


/data 【站点缓存数据等文件】


需求有读取权限和写入修正权限 //建议去掉执行权限//0666


/html 【HTML文档默认目录】


需求有读取修正和创建权限 //建议去掉执行权限 //0666


/templets【模板目录】


需求有读取 修正写入 权限 //建议去掉执行权限 //0666


/uploads 【附件目录】


需求写入读取权限 //建议去掉执行权限//0666


/company 【企业黄页程序目录】


需求读取和执行权限 //建议去掉写入权限//0555


/special 【专题文件目录】


需求执行、读取、写入和修正权限 //0755


/book 【书库模块程序目录】


需求执行、读取、写入和修正权限 //0755


/ask 【问答模块程序目录】


需求执行和读取权限 //建议去掉写入权限//0555


/group 【圈子模块程序目录】


需求执行和读取权限 //建议去掉写入权限 //0555
作者:NCZB007 发表于2017/11/22 15:28:30 原文链接
阅读:147 评论:0 查看评论

React Native 入门(十二) - Fetch 网络请求

$
0
0

当前 RN 版本:0.50
操作环境:Windows 10

文章同步自简书:http://www.jianshu.com/p/b3c1b4298d18

不知不觉中,RN 0.50 已经发布了。两个多礼拜没有接触 RN 了,已经忘得差不多了,赶紧再恶补一下写写博客,否则真的会忘得一干二净。这篇文章简单介绍 RN 中的网络请求。

使用 Fetch

Fetch 使用起来很简单,只需要简单的一行代码就可以实现网络请求:

fetch(url)

它还可以有第二个可选的参数,用来进行请求的配置。比如指定 header 参数、指定 GET 或 POST 方法、提交表单数据等等。可以参考 Fetch请求文档 来查看所有可用的参数。

var options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
};

fetch(url, options);

发起请求之后要对请求到的数据进行处理, Fetch 使用链式调用的方式来进行操作,格式如下:

fetch('https://facebook.github.io/react-native/movies.json')
      .then((response) => {
        // 获取到网络请求返回的对象
        response.json()
      })
      .then((result) => {
        // 网络请求成功,处理请求到的数据
      })
      .catch((error) => {
        // 网络请求失败,处理错误信息
      });

你还可以使用 ES7 标准中的 async/await 语法:

// 注意这个方法前面有 async 关键字
  async getMoviesFromApi() {
    try {
      // 注意这里的 await 语句,其所在的函数必须有 async 关键字声明
      let response = await fetch('https://facebook.github.io/react-native/movies.json');
      let result = await response.json();
      return responseJson.movies;
    } catch(error) {
      console.error(error);
    }
  }

Promise 封装

Promise 是专门用来处理异步请求的。由于我对它也不是很熟悉,大家可以在网上查询更多的资料。

我们写个工具类 HttpUtil.js 并在其中利用 Promise 封装 getpost 方法,代码参考如下。

export default class HttpUtil {

  /**
   * 利用 Promise 的 get 方式请求
   * @param url
   * @returns {Promise}
   */
  static get(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
          .then(response => response.json())
          .then(result => resolve(result))
          .catch(error => reject(error))
    })
  }

  /**
   * 利用 Promisepost 方式请求
   * @param url
   * @param params
   * @returns {Promise}
   */
  static post(url, params) {
    return new Promise((resolve, reject) => {
      fetch(url, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(params)
      })
          .then(response => response.json())
          .then(result => resolve(result))
          .catch(error => reject(error))
    })
  }
}

接下来我们需要进行网络请求的时候就可以直接使用了。

export default class FetchTest extends Component {

  constructor(props) {
    super(props);
    this.state = {
      text: '返回结果'
    }
  }

  get() {
    HttpUtil.get('https://facebook.github.io/react-native/movies.json')
        .then(result => this.setState({text: JSON.stringify(result)}))
        .catch(error => console.error(error))
  }

  post() {
    var data = {username: 'ayuhani', password: '123456'}
    HttpUtil.post('http://rapapi.org/mockjsdata/26411/ayuhani/post', data)
        .then(result => this.setState({text: JSON.stringify(result)}))
        .catch(error => console.error(error))
  }

  render() {
    return <View style={{flex: 1}}>
      <View style={{margin: 16}}>
        <Button
            title={'get'}
            onPress={() => this.get()}
        />
        <Button
            title={'post'}
            onPress={() => this.post()}
        />
        <Text style={{marginTop: 16}}>{this.state.text}</Text>
      </View>
    </View>
  }
}

看一下运行效果:

我是效果图

代码确实简洁了不少,当然应该还有更好的封装方法,以后学到了再来分享吧。

作者:qq_24867873 发表于2017/11/22 15:55:18 原文链接
阅读:129 评论:0 查看评论

Unity3D-使用Firebase中的云消息推送

$
0
0

在此记录下使用Firebase云消息推送的过程:

在Firebase的console里面,选中自己的项目,左边菜单栏有个Project Overview的标签,有个齿轮图标,点进去可以看到项目设置;


我们需要在“云消息推送”的子标签里面上传一个“APNs 身份验证密钥”,该文件是需要你去苹果开发者网址下载一个.p8的密钥文件,等于是拿到苹果的远程推送的授权一样。接下来,我们就去 https://developer.apple.com/account/ios/certificate/ 这个里面的Keys下方创建一个APNs的文件



点击右边那个“+”号,添加一个新文件,取一个名字,勾上APNs



创建完毕之后,就可以点下载按钮,把这个文件下载下来啦,下载下来的就是.p8文件了!

然后到Firebase的console上面,把下载下来的.p8文件上传到第一张图 APNs 身份验证 的位置



其中,密钥ID是指刚刚生成的.p8文件的Key ID



而应用前缀ID是苹果开发者网址里面展示AppID里面的你自己的项目AppID下面的一个前缀,可以在苹果开发者网址看到



这里设置完毕之后,就可以愉快的使用Firebase的云消息推送啦,不过你得使用真机测试,否则不会起作用哦!


使用就很简单了,其实都不需要在代码中添加额外代码,但是,如果需要对接受到的消息进行处理,那么还是要添加代码的

加入头文件:

using Firebase;
using System.Threading.Tasks;
using Firebase.Unity.Editor;
using Firebase.Messaging;


然后在启动的时候初始化,设置监听回调:

public void InitMessaging(){
        FirebaseMessaging.TokenReceived += OnMessagingTokenReceived;
        FirebaseMessaging.MessageReceived += OnMessageReceived;
    }
    void FreeMessaging(){
        FirebaseMessaging.TokenReceived -= OnMessagingTokenReceived;
        FirebaseMessaging.MessageReceived -= OnMessageReceived;
    }
    void OnMessagingTokenReceived(object sender, TokenReceivedEventArgs token){
        Debug.Log("Received Registration Token: " + token.Token);
    }
    void OnMessageReceived(object sender, MessageReceivedEventArgs args){
        Debug.Log("Received a new message from: " + args.Message.From);
        Debug.Log("Message ID: " + args.Message.MessageId);
        Debug.Log("Message Badge: " + args.Message.Notification.Badge);
        Debug.Log("Message Title: " + args.Message.Notification.Title);
        Debug.Log("Message Body: " + args.Message.Notification.Body);
    }

另外,如果想添加图标上的badge number,是可以直接在Firebase的console上面设置的,在编辑消息里面,高级选项中设置是否有声音,是否有iOS标志,以及标志的数量



到这里,云消息推送就完成啦,以后就只要在Firebase发号施令啦~





作者:pz789as 发表于2017/11/22 16:42:55 原文链接
阅读:114 评论:0 查看评论

NOIP2017成绩(普及T1)

$
0
0

标签:模拟
题目描述
牛牛最近学习了C++入门课程,这门课程的总成绩计算方法是:
总成绩=作业成绩×20%+小测成绩×30%+期末考试成绩×50%
牛牛想知道,这门课程自己最终能得到多少分。
输入输出格式
输入格式:
输入文件只有1行,包含三个非负整数A、B、C,分别表示牛牛的作业成绩、小测成绩和期末考试成绩。相邻两个数之间用一个空格隔开,三项成绩满分都是100分。
输出格式:
输出文件只有1行,包含一个整数,即牛牛这门课程的总成绩,满分也是100分。
输入输出样例
输入样例#1:
100 100 80
输出样例#1:
90
输入样例#2:
60 90 80
输出样例#2:
79
说明
输入输出样例1说明
牛牛的作业成绩是100分,小测成绩是100分,期末考试成绩是80分,总成绩是100×20%+100×30%+80×50%=20+30+40=90。
输入输出样例2说明
牛牛的作业成绩是60分,小测成绩是90分,期末考试成绩是80分,总成绩是60×20%+90×30%+80×50%=12+27+40=79。
数据说明
对于30%的数据,A=B=0。
对于另外30%的数据,A=B=100。
对于100%的数据,0<=A,B,C<=100且A,B,C都是10的整数倍

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#ifdef WIN32
#define LL "%I64d"
#else 
#define LL "%lld"
#endif
using namespace std;
inline ll read()
{
    ll f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int main()
{
    int a,b,c;
    cin>>a>>b>>c;
    cout<<a*0.2+b*0.3+c*0.5<<endl;
    return 0;
}
作者:qwerty1125 发表于2017/11/22 17:00:05 原文链接
阅读:129 评论:1 查看评论

Android--gson将list转化为json字符串

$
0
0

在项目中,需要将list转换为json字符串,发送给服务器,在实现过程中先建立一个实体类App,但是得到的只是list的最后一组数据,查找原因:要将new App放在for循环里面,每次新建一个对象就ok了。

具体代码:

public class App {
    String label;
    String packageName;

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }


}

public class JsonInfo {
    public static ArrayList<AppInfo> appInfoList;
    public static List<App> apps = new ArrayList<>();
    static App app;
    public static void info() {
        Gson gson = new Gson();
        ApplicationList list = new ApplicationList();
        appInfoList = list.AppList();
        for (AppInfo appInfo : appInfoList) {
            app = new App();
            String label = appInfo.getLabel();
//            Log.e("label",label);
            String packageName = appInfo.getPackageName();
//            Log.e("packageName",packageName);
            app.setLabel(label);
            app.setPackageName(packageName);
            apps.add(app);
        }
        String jsonApp = gson.toJson(apps);
        WriteSd(jsonApp);
    }
    private static void WriteSd(String str)
    {
        try{
            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
            String foldername = Environment.getExternalStorageDirectory().getPath()+ "/360";
            File folder = new File(foldername);
            if (folder == null || !folder.exists()) {
                folder.mkdir();
            }
            FileOutputStream out = new FileOutputStream(folder.getCanonicalPath()+ "/"+"json.txt");
            out.write(str.getBytes());
            out.close();

        }catch(Exception e){
            e.printStackTrace();
        }

    }
}


作者:chaoyu168 发表于2017/11/22 17:03:34 原文链接
阅读:134 评论:0 查看评论

【拜小白opencv】39-形态学滤波4——闭运算

$
0
0

常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。

本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。

博主机器配置为:VS2013+opencv2.4.13+Win-64bit。

若本文能给读者带来一点点启示与帮助,我就很开心了。

====================分割线====================


1-开运算

形态学闭运算操作同样能去除噪声及平滑目标边缘等功能,其数学表达式如下:




  • 闭运算(Closing Operation),其实就是先膨胀再腐蚀的结果。
  • 形态学闭运算能够排除小型黑洞(黑色区域),消除低于邻近点的孤立点,达到去噪的作用。
  • 闭运算的结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算一般会将狭窄的缺口连接起来形成细长的弯口,并消除小孔洞
===============分割线=================

2-morphologyEx()函数

作用:该函数可以进行形态学滤波的操作,里面包含了开运算、闭运算、形态学梯度、顶帽、黑帽、腐蚀、膨胀等。
void morphologyEx( InputArray src, OutputArray dst,
                                int op, InputArray kernel,
                                Point anchor=Point(-1,-1), int iterations=1,
                                int borderType=BORDER_CONSTANT,
                                const Scalar& borderValue=morphologyDefaultBorderValue() );
参数解释:
  • 参数1:输入图像,即源图像,填Mat类的对象即可。图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
  • 参数2:OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 参数3:int类型的op,表示形态学运算的类型,可以是如下之一的标识符:
————MORPH_OPEN – 开运算(Opening operation)
————MORPH_CLOSE – 闭运算(Closing operation)
————MORPH_GRADIENT -形态学梯度(Morphological gradient)
————MORPH_TOPHAT - “顶帽”(“Top hat”)
————MORPH_BLACKHAT - “黑帽”(“Black hat“)
————MORPH_ERODE - “腐蚀”
————MORPH_DILATE - “膨胀”

————另有CV版本的标识符也可选择,如CV_MOP_CLOSE,CV_MOP_GRADIENT,CV_MOP_TOPHAT,CV_MOP_BLACKHAT等,这应该是OpenCV1.0系列版本遗留下来的标识符,和上面的“MORPH_OPEN”一样的效果。 

  • 参数4:InputArray类型的kernel,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement()配合这个参数的使用。getStructuringElement()函数会返回指定形状和尺寸的结构元素(内核矩阵)。关于getStructuringElement()函数,请见文章里有相关讲解:【拜小白opencv】36-形态学滤波1——腐蚀
  • 参数5:Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。
  • 参数6:int类型的iterations,迭代使用函数的次数,默认值为1。
  • 参数7:int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_ CONSTANT。
  • 参数8:const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

使用morphologyEx()函数,一般我们只需要填前面的四个参数,后面的四个参数都有默认值。
===================分割线================

3-代码演示

/*
功能:形态学滤波:闭运算。 本质就是先膨胀后腐蚀的过程。
*/

#include <opencv2/core/core.hpp>                
#include <opencv2/highgui/highgui.hpp>                
#include <opencv2/imgproc/imgproc.hpp>               
#include <iostream>              
using namespace std;
using namespace cv;

int main()
{
	Mat srcImage, dstImage; //源图像,输出图像
	//---------【1】读取源图像并检查图像是否读取成功---------      
	srcImage = imread("D:\\OutPutResult\\ImageTest\\xing.jpg");
	if (!srcImage.data)
	{
		cout << "读取图片错误,请重新输入正确路径!\n";
		system("pause");
		return -1;
	}
	imshow("【源图像】", srcImage);
	//---------【2】获取自定义核---------
	Mat element = getStructuringElement(MORPH_RECT, Size(7, 7));
	//---------【3】进行闭运算操作---------
	morphologyEx(srcImage, dstImage, MORPH_CLOSE, element);
	//---------【4】显示效果图---------
	imshow("【效果图--闭运算操作】", dstImage);
	waitKey(0);
	return 0;
}
================分割线===================

4-显示结果



===================分割线=================

5-程序说明

为了观察效果,本例中核的设置为7*7,该参数可以根据自己需要进行调节。
例子中,morphologyEx()函数的第三个参数,同学可以右键进行”查看定义“,看看都有什么,自己换个参数,看看会不会有什么效果。



参考文章:【OpenCV入门教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑


==================END====================

作者:sinat_36264666 发表于2017/11/22 17:06:32 原文链接
阅读:87 评论:0 查看评论

centos 7 下搭建 tensorflow+keras 深度学习环境

$
0
0

之前在阿里云服务器上搭建过 docker+tensorflow+keras 的深度学习环境,由于服务器停用等一系列问题,不得不在本地服务器重新搭建环境,本次以 root 用户直接操作,不再使用 docker 容器。作为分享和备忘,特此记录。

1.python2.7.5 安装

centos 系统自带 python,此步骤可省略(Mac Os 同样可省略此步骤),当然,也可升级 python3.x 版本。

2.python-pip 安装

yum install python-pip python-devel

安装完成后,测试一下:

pip --version

若显示未找到命令,则如下形式再次安装:

yum -y install epel-release
yum install python-pip

安装完成后,再次测试结果如下则表示 pip 安装成功:

这里写图片描述

3.安装tensorflow

这里给一个国内镜像源,十分方便,资源丰富,避免了各种墙外麻烦:https://mirrors.tuna.tsinghua.edu.cn/help/tensorflow/

这里写图片描述

可根据需要自行配置下载版本,十分方便,解决了你满世界找镜像的麻烦。安装成功后,可在 pip list 中找到 tensorflow,如下图所示:
这里写图片描述

4.安装 numpy、scipy 库

pip install numpy
pip install scipy

5.安装 keras

git clone https://github.com/fchollet/keras.git
cd keras/
python setup.py install

安装完成后,同样查看 pip list 如下图:
这里写图片描述

如果能走到这里,那么恭喜你装好了,去深度学习的大海里遨游吧!

安装有问题可留言,可探讨!

作者:huangfei711 发表于2017/11/22 17:31:16 原文链接
阅读:103 评论:0 查看评论

常见操作便捷化方法及其实例

leetcode-387. First Unique Character in a String

$
0
0

387. First Unique Character in a String

Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.

Examples:

s = "leetcode"
return 0.

s = "loveleetcode",
return 2.

Note: You may assume the string contain only lowercase letters.


题意:

找出字符串 s 中第一个不重复的字符,并返回他的序号


解法:

一开始就想着用map来记录每次字符出现的次数,然后找到出现一次的字符就返回序号就可以了

但是提交过后发现用时太久了,用了 111ms

class Solution {
    public int firstUniqChar(String s) {
        if(s.length()==0) return -1;
        int solu = -1;
        Map<Character,Integer> map = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            if(map.get(s.charAt(i))!= null){
                map.put(s.charAt(i),map.get(s.charAt(i))+1);
            }else{
                map.put(s.charAt(i),1);
            }
        }
        for (int i = 0; i < s.length(); i++) {
            if(map.get(s.charAt(i))==1) {
                solu = i;
                break;
            }
        }
        return solu;
    }
}//111ms


看了diss中的解法,发现用数组就会快很多很多,,思路还是一致的。

class Solution {
    public int firstUniqChar(String s) {
        int[] arr = new int[27];
		for (int i = 0;i < s.length() ;i++ ) 
			arr[s.charAt(i) - 'a'] ++;
		for (int i = 0;i< s.length() ;i++ ) 
			if(arr[s.charAt(i) - 'a'] == 1) return i;
		return -1;
    }
}//28ms


作者:qq_32832023 发表于2017/11/22 18:42:21 原文链接
阅读:81 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>